← writing
·2 min read

Fixing Claude Code OAuth token revoked when switching accounts

Claude Code caches OAuth tokens in at least four places: environment variables, macOS Keychain, dotfiles, and XDG config directories. When you switch from one Anthropic account to another — say, moving to a different Max plan email — the old token stays cached and you get a "token revoked" error on every launch. The CLI never prompts you to re-authenticate because it thinks it already has a valid token.

The fix is a full credential purge. Here's every location you need to hit:

1. Remove hardcoded tokens from your shell config

sed -i '' '/CLAUDE_CODE_OAUTH_TOKEN/d' ~/.zshrc

If you exported the token directly in .zshrc or .bashrc at any point, that stale value loads before Claude Code even starts. Delete the line.

2. Unset lingering env vars in the current session

unset CLAUDE_CODE_OAUTH_TOKEN
unset ANTHROPIC_API_KEY
source ~/.zshrc

The shell session still holds the old value in memory even after editing the file.

3. Clear macOS Keychain

security delete-generic-password -s "Claude Code" 2>/dev/null

Claude Code stores credentials in the system keychain. This survives shell restarts and even npm updates.

4. Delete all cached credential directories

rm -rf ~/.claude
rm -f ~/.claude.json
rm -rf ~/.config/claude-code/
rm -rf ~/.config/@anthropic-ai/

Four separate locations. Miss one and the stale token comes back.

5. Clear tmux environment (if applicable)

Tmux maintains its own environment that survives terminal restarts. If you use tmux: tmux set-environment -gu CLAUDE_CODE_OAUTH_TOKEN or just tmux kill-server before reopening.

6. Restart terminal completely

Close the terminal app entirely and reopen. source ~/.zshrc is not enough — some env vars get inherited from the parent process.

7. Update Claude Code

npm update -g @anthropic-ai/claude-code

8. Login fresh

claude

When the OAuth page opens, use an incognito browser window. This prevents your browser's cached Google/Anthropic session from auto-selecting the wrong account. Pick the correct Max plan email explicitly.

If you use multiple accounts permanently, isolate their configs to prevent the Keychain collision entirely:

alias claude2='CLAUDE_CONFIG_DIR=~/.claude-account2 claude'

Now claude uses your primary account and claude2 uses the second. Separate config dirs, separate Keychain entries, no overwrites.


The root cause: OAuth token caching is distributed across shell config, OS keychain, and multiple XDG directories. There's no single claude logout that clears all of them. When switching accounts, you need to scorched-earth the credential layer and start clean.