Login reports success but never persists the credential (macOS Keychain) — silent auth loop on 2.1.223 and 2.1.232
Summary
claude login completes browser OAuth and prints Login successful, but the credential is never written to the macOS Keychain. The next command reports not-logged-in, so every session demands a fresh login and every login silently persists nothing. Reproduced 4 times across two versions.
The most useful diagnostic detail: the token demonstrably works in-process before the write fails (evidence 3 below), which narrows this to the credential-persistence step rather than the OAuth exchange.
Environment
- macOS 15.x (Darwin 25.5.0), Apple Silicon
- Claude Code 2.1.223, then 2.1.232 after a clean
npm i -g @anthropic-ai/claude-code— identical behavior on both - zsh; default login keychain, unlocked; standard keychain search list
- Subscription account (not API billing)
Steps to reproduce
claude login, complete the browser OAuth flow- Observe
Login successful - Run any command, or
claude loginagain → reports not logged in security find-generic-password -s "Claude Code-credentials"→ item not found
Evidence
- No Keychain item is ever created.
security find-generic-password -s "Claude Code-credentials"returns "could not be found" after every successful login. Prior history: a stale item from February existed with its modification date frozen months in the past, meaning logins were "succeeding" without ever touching it. That item was deleted during diagnosis; since then no item is created at all. - No file fallback.
~/.claude/.credentials.jsondoes not exist after login. - The token authenticates in-process, then fails only at persistence.
~/.claude.json'soauthAccountblock carries aprofileFetchedAttimestamp from the failing login session itself, with fully refreshed profile fields (billing type, account and org identifiers, display name). So the process exchanged the OAuth code, made a successful authenticated API call, and wrote the non-secret results to config — only the secret write never happened, and without an error. - The Keychain itself is healthy. From the same user in the same terminal:
security add-generic-password -s probe -a probe -w x→ write OK, read-back OK, delete OK. - Nothing is diverting auth. No
apiKeyHelper, noprimaryApiKey, noANTHROPIC_*variables insettings.json,settings.local.json,.zshrc,.zshenv,.zprofile, or/etc/zshenv. Config file is 0600 and user-owned. - Possibly related, seen in the same session: an
Auto-update failedtoast suggestingclaude doctoror a global npm reinstall.
Expected
Login successful should imply the credential was durably stored — or the CLI should surface an explicit error when the Keychain write fails, rather than reporting success and reading back nothing.
Impact
OAuth login is effectively unusable on this machine. A knock-on effect worth flagging: because there is no persisted credential and no file fallback, any non-interactive invocation loses authentication entirely — launchd agents, cron jobs, and CI wrappers that spawn claude inherit no shell profile, so they cannot pick up an environment-variable workaround either. Automation that previously worked via the Keychain silently stops authenticating.
Workaround
claude setup-token works and stays on subscription billing: it returns a long-lived token to the terminal, which can be exported as CLAUDE_CODE_OAUTH_TOKEN. Verified working here via a headless round-trip. Note this only helps processes that can see the variable — see the automation caveat above.
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗