Claude Code picks exactly one authentication method per session using a fixed priority chain. If you have the wrong method winning, you get silent failures rather than clear errors.
The chain, from highest to lowest priority:
- Cloud provider env vars (
CLAUDE_CODE_USE_BEDROCK,CLAUDE_CODE_USE_VERTEX,CLAUDE_CODE_USE_FOUNDRY) ANTHROPIC_AUTH_TOKEN: Bearer token for LLM gatewaysANTHROPIC_API_KEY: direct API key from ConsoleapiKeyHelperscript: shell command returning a keyCLAUDE_CODE_OAUTH_TOKEN: long-lived OAuth token fromclaude setup-token- Subscription OAuth: the default for Pro/Max/Team/Enterprise
Interactive use (default)
Run claude in your terminal. On first launch, a browser window opens for OAuth login. Complete it and credentials are saved automatically.
Credential storage locations:
- macOS: encrypted Keychain
- Linux:
~/.claude/.credentials.jsonwith mode0600 - Windows:
%USERPROFILE%\.claude\.credentials.json
To log out: /logout in a session or claude auth login to re-authenticate.
CI and scripts: claude setup-token
Generate a one-year OAuth token for environments where browser login isn’t available:
claude setup-token
The command runs the OAuth flow and prints the token. It does not save it. Copy it and set it as an environment variable:
export CLAUDE_CODE_OAUTH_TOKEN=your-token
This token requires a Pro, Max, Team, or Enterprise plan. It is scoped to inference only.
Direct API key: ANTHROPIC_API_KEY
For Console API customers or when you need to bypass subscription limits:
export ANTHROPIC_API_KEY=sk-ant-...
In interactive sessions, Claude Code prompts once to approve the key. In non-interactive mode (-p), the key is always used when present. To change an approved key later, use the “Use custom API key” toggle in /config.
LLM gateway: ANTHROPIC_AUTH_TOKEN
When routing through a proxy that expects a Bearer token (LiteLLM, custom gateway):
export ANTHROPIC_AUTH_TOKEN=your-bearer-token
export ANTHROPIC_BASE_URL=https://your-gateway.example.com
The token is sent as Authorization: Bearer. This is distinct from ANTHROPIC_API_KEY, which is sent as X-Api-Key. Use ANTHROPIC_AUTH_TOKEN when the gateway expects Bearer format.
Dynamic credentials: apiKeyHelper
For rotating credentials, short-lived tokens from a vault, or any case where the key changes between sessions:
{
"apiKeyHelper": "~/.local/bin/get-claude-key"
}
The script must print a single API key to stdout. Claude Code calls it after 5 minutes or on a 401 response. Set a custom refresh interval:
export CLAUDE_CODE_API_KEY_HELPER_TTL_MS=60000
Check which method is active
/status
The status panel shows the active auth method and settings sources.
Footguns
ANTHROPIC_API_KEY in your shell profile overrides your subscription silently. If you set an API key from a previous employer or project and forgot about it, Claude Code uses that key instead of your subscription OAuth. You see “This organization has been disabled” errors even though your subscription is active. Run unset ANTHROPIC_API_KEY and check ~/.zshrc or ~/.bashrc for stale export lines.
CLAUDE_CODE_OAUTH_TOKEN is inference-only. The Remote tab in the VS Code extension shows “requires full-scope login” when this token is active. Run claude auth login via the full OAuth flow to get a full-scope token for Desktop and Remote sessions.
--bare mode ignores CLAUDE_CODE_OAUTH_TOKEN. If your CI script uses both --bare and CLAUDE_CODE_OAUTH_TOKEN, authentication fails. Use ANTHROPIC_API_KEY or apiKeyHelper for bare-mode scripts.
apiKeyHelper, ANTHROPIC_API_KEY, and ANTHROPIC_AUTH_TOKEN apply to CLI sessions only. Claude Desktop and remote sessions use OAuth exclusively and ignore these variables.
If apiKeyHelper takes longer than 10 seconds, Claude Code shows a warning in the prompt bar. This doesn’t break auth, but it stalls every prompt refresh. Optimize the script to return quickly, or cache the key locally with a TTL.
When NOT to use each method
Use ANTHROPIC_API_KEY only for direct Console API access. If you have a subscription and want the Remote tab, Desktop, or Cowork features, use OAuth instead. An API key in the environment takes priority and blocks those features.
Do not use CLAUDE_CODE_OAUTH_TOKEN for --bare scripted pipelines. Use ANTHROPIC_API_KEY or apiKeyHelper there.
Do not use apiKeyHelper for static non-rotating keys. The overhead of a subprocess call on every refresh is not worth it for a fixed string. Use ANTHROPIC_API_KEY for static keys.