cxa is a tiny Codex account switcher for macOS and Linux.
It keeps multiple Codex auth.json files in one folder and switches the active account by pointing ~/.codex/auth.json at the selected file with a symlink.
No runtime dependencies beyond Bash and the Codex CLI.
$ cxa
Select Codex account
> personal (active)
work
client
↑/↓ move · Enter select · q cancel
You can also switch without the menu:
cxa workThere are three ways to add an auth profile.
1. Import a specific auth file
Pass the auth JSON file path to cxa get:
cxa get auth-file.json
cxa get ~/Downloads/auth.jsoncxa then asks for the profile name:
$ cxa get ~/Downloads/auth.json
Profile name: work
Saved Codex auth: work
Switch with: cxa work
The file is copied to:
~/.codex/accounts/work.json
The argument is always treated as a file path, not as a profile name. So cxa get work means “import the file named work” and fails if that file does not exist.
2. Copy the current Codex auth — default
Run:
cxa getThe default option is to copy the current ~/.codex/auth.json:
How do you want to add an auth profile?
> Copy current ~/.codex/auth.json
Login to another Codex account
↑/↓ move · Enter select · q cancel
Choose [1]:
Profile name: personal
Just press Enter at Choose [1].
3. Login to another account
Run cxa get, move to Login to another Codex account with ↑/↓, and press Enter. cxa opens an isolated codex login, gets the resulting auth.json, then asks for the profile name and saves it under ~/.codex/accounts/.
Clone the repository and run:
./install.shBy default, the installer copies the CLI into a stable system-local location first:
/usr/local/lib/cxa/cxa
and then creates the command symlink:
/usr/local/bin/cxa -> /usr/local/lib/cxa/cxa
This means the installed command no longer depends on where you cloned the repository. You can delete or move the checkout after installation.
On macOS/Linux, /usr/local may require administrator permissions. The installer uses sudo only for the system install files when necessary; your ~/.codex account files are always created as your normal user.
git clone <repository-url> cxa
cd cxa
./install.shAfter that:
cxa helpIf you do not want to use sudo, install under your home directory:
PREFIX="$HOME/.local" ./install.shThat produces:
~/.local/lib/cxa/cxa
~/.local/bin/cxa -> ~/.local/lib/cxa/cxa
If ~/.local/bin is not in your PATH, add:
export PATH="$HOME/.local/bin:$PATH"You can also override the prefix or the two destination directories explicitly:
PREFIX=/opt/local ./install.shor:
APP_DIR=/opt/cxa BIN_DIR=/usr/local/bin ./install.shcxa Interactive account picker
cxa <name> Switch directly to an account
cxa get Pick Copy current/Login with ↑/↓, then ask profile name
cxa get <auth-file.json> Import that auth file, then ask profile name
cxa list List saved accounts
cxa current Print the selected account
cxa help Show help
cxa version Print version
Examples:
# Interactive picker
cxa
# Direct switch
cxa personal
cxa work
# .json is optional when SWITCHING an existing profile
cxa work.json
# Import a downloaded/copied auth file
cxa get ~/Downloads/auth.json
# -> Profile name: client
# Copy the auth Codex is currently using (default option)
cxa get
# -> Enter on option 1
# -> Profile name: personal
# Login to another account
cxa get
# -> choose 2
# -> complete Codex login
# -> Profile name: work
# See all accounts
cxa list
# Machine-friendly current account
cxa currentBy default:
~/.codex/
├── auth.json -> /Users/you/.codex/accounts/personal.json
├── accounts/
│ ├── personal.json
│ ├── work.json
│ └── client.json
├── config.toml
├── sessions/
└── ...
Only authentication is switched. Your normal Codex home stays the same, so config, sessions, skills and other Codex state are not duplicated.
If CODEX_HOME is set, cxa uses that directory instead of ~/.codex.
cxa get has three source flows:
cxa get <file> Import that exact auth file -> ask profile name -> save to accounts/
cxa get Copy current auth.json (default selection) -> ask profile name
cxa get Login selection -> isolated codex login -> ask profile name
For the login flow, cxa creates a temporary isolated CODEX_HOME, writes:
cli_auth_credentials_store = "file"and runs:
codex loginThe resulting temporary auth.json is imported into ~/.codex/accounts/<profile>.json, then the temporary directory is removed. Your currently active Codex auth is not replaced during that login.
If you already have a normal file at:
~/.codex/auth.json
cxa does not silently delete it.
On the first switch it moves the existing file to a timestamped profile such as:
~/.codex/accounts/imported-20260925-141500.json
and then creates the active symlink.
You can keep that profile, rename it manually, or add a clean named login with cxa get personal.
Codex can refresh and rewrite the active auth file. The current file-auth implementation opens $CODEX_HOME/auth.json with truncate/write semantics, which follows a normal filesystem symlink. That means refreshed credentials are written back into the selected account file instead of leaving the stored profile stale.
Relevant Codex source:
codex-rs/login/src/auth/storage.rs— file auth storage reads/writes$CODEX_HOME/auth.jsoncodex-rs/config/src/config_toml.rs—cli_auth_credentials_store
There are also community reports around copied OAuth auth files becoming stale after refresh-token rotation, which is another reason this project switches the actual backing file rather than maintaining independent copies.
cxa switches file-based Codex credentials.
Current Codex source documents file as the default credential backend, but if your ~/.codex/config.toml explicitly contains something like:
cli_auth_credentials_store = "keyring"or:
cli_auth_credentials_store = "auto"set it to:
cli_auth_credentials_store = "file"for normal Codex runs that you want cxa to switch.
The installer warns if it detects an explicit non-file setting. cxa get itself always forces file storage only for its isolated login operation.
Switch accounts before starting a new Codex session.
A Codex process or editor integration that is already running may keep authentication state in memory. If it still shows the previous account after a switch, restart that Codex process/editor integration.
auth.json files contain credentials. Treat them as secrets.
cxa creates the accounts directory with user-only permissions where supported and sets saved auth files to mode 0600.
Do not commit this directory:
~/.codex/accounts/
Never add real auth JSON files to this repository.
./uninstall.shThis removes both:
/usr/local/bin/cxa
/usr/local/lib/cxa/cxa
when they match the cxa installation layout. It intentionally leaves your Codex auth files under ~/.codex/accounts/ untouched.
Run the smoke tests:
make testInstall from the current checkout:
make installUninstall:
make uninstall- macOS or Linux
- Bash
- Codex CLI for
cxa get - A terminal with ANSI escape support for the interactive picker
Direct switching (cxa work) and listing do not execute Codex themselves.
MIT