Two ways to run multiple Claude Code subscriptions (personal + work) on one machine, side-by-side, without a re-login every time you switch.
Use long-lived OAuth tokens + direnv. The keychain-swap approach originally in this gist has a subtle bug: Anthropic's short-lived OAuth credentials rotate on every refresh, so a snapshot you saved to disk goes stale within hours. Symptom — "please log in" every time you return to the other profile. Long-lived tokens (claude setup-token, 1-year TTL, no rotation) sidestep the problem entirely.
Each subscription gets its own CLAUDE_CODE_OAUTH_TOKEN stored in a file. direnv swaps the env var by directory. No Keychain, no rotation races.
# 1. Generate personal token (run in any terminal, logged into personal account)
claude setup-token
# Save output → ~/.claude-personal-token
chmod 600 ~/.claude-personal-token
# 2. Generate work token (run in a shell logged into the work account)
mkdir -p ~/.claude-work
claude setup-token
# Save output → ~/.claude-work/token
chmod 600 ~/.claude-work/token
# 3. Personal default in ~/.zshrc:
cat >> ~/.zshrc <<'EOF'
# Claude Code multi-account via long-lived tokens + direnv
[ -f ~/.claude-personal-token ] && \
export CLAUDE_CODE_OAUTH_TOKEN="$(cat ~/.claude-personal-token)"
eval "$(direnv hook zsh)"
EOF
# 4. Per-project override in ~/projects/work/.envrc:
cat > ~/projects/work/.envrc <<'EOF'
export CLAUDE_CONFIG_DIR=$HOME/.claude-work
export CLAUDE_CODE_OAUTH_TOKEN="$(cat "$CLAUDE_CONFIG_DIR/token")"
EOF
direnv allow ~/projects/work
# 5. Clear stale Keychain OAuth (so Claude Code reads the env token cleanly)
security delete-generic-password -s "Claude Code-credentials" -a "$USER" 2>/dev/nullOpen a fresh terminal. In ~/projects/work → work account. Anywhere else → personal. Both persist independently.
claude setup-token emits sk-ant-oat01-... — a 1-year OAuth token tied to your Claude subscription. It counts against your Pro/Max quota (not API billing), and critically does not rotate, so file-based storage stays valid for the full year.
CLAUDE_CONFIG_DIR isolates per-project settings, history, and MCP state. Combined with direnv, each project gets its own Claude profile automatically — no wrapper function, no manual switching.
- Already-running sessions don't see new env vars. Restart your shell after editing
.zshrc/.envrc. ANTHROPIC_API_KEYtakes precedence overCLAUDE_CODE_OAUTH_TOKENif both are set. Don't mix them.- Third-party tools are off-limits. Since April 2026, Anthropic's ToS forbids feeding these tokens to Cursor, Cline, Windsurf, OpenClaw, etc. Claude Code and the official
claude-code-actionare fine. - Status line may display "API" instead of "Subscription". Cosmetic — billing still goes against your subscription quota.
- One active long-lived token per subscription. Re-running
claude setup-tokeninvalidates the previous one.
The original scripts in this gist (claude-switch-auth, zshrc-wrapper.sh, dot-envrc) swap macOS Keychain entries between saved profiles. This works for API keys (sk-ant-api03-..., no rotation), but breaks with OAuth subscriptions: the refresh token rotates on every use, so the snapshot you saved for profile A is already invalid by the time you switch away and back. The wrapper silently overwrites the fresh Keychain entry with the stale file, logging you out.
Keep these files if you have mixed OAuth + API key setups and want per-directory API-key swapping. For OAuth-only subscriptions, use the recommended approach above.
| File | Purpose |
|---|---|
README.md |
this doc |
dot-envrc-token |
.envrc template for the recommended token approach |
dot-envrc |
.envrc template for the legacy Keychain approach |
claude-switch-auth |
legacy Keychain-swap script (works cleanly only for API keys) |
zshrc-wrapper.sh |
legacy .zshrc wrapper for directory-based Keychain swap |
- Authentication — Claude Code Docs
- Using Claude Code with your Pro or Max plan
- direnv
- ming86/cc-account-switcher — original Keychain swapper (archived)
- fairy-pitta/cc-account-switcher — actively maintained fork
MIT