[BUG] v2.0.14 macOS Keychain issue - OAuth authentication doesn't persist without security unlock-keychain each session
[UPDATE - This is NOT a service name mismatch]
See comments below regarding use of "security unlock-keychain ~/Library/Keychains/login.keychain-db" in each session to allow access to stored credentials from /login on macOS.
Original report follows:
----------------------------------------
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
OAuth login (/login) successfully stores credentials in macOS Keychain under service name "Claude Code-credentials", but Claude Code v2.0.14 startup attempts to read from "Claude Code" (without -credentials suffix). This service name mismatch causes authentication to fail on every new session.
Evidence:
bash
OAuth /login writes credentials here - this succeeds:
$ security find-generic-password -s "Claude Code-credentials" -w
{"claudeAiOauth":{"accessToken":"sk-ant-oat01-...","refreshToken":"..."}}
Claude Code startup reads from here - this fails:
$ security find-generic-password -s "Claude Code" -w
security: SecKeychainSearchCopyNext: The specified item could not be found in the keychain.
Impact:
Authentication only works in the session where /login was executed
Every new terminal session requires re-authentication with "Invalid API key - Please run /login"
Affects both local terminal sessions AND remote SSH sessions
Makes Claude Code unusable without repeated logins
What Should Happen?
Claude Code should use consistent service names for both writing and reading credentials from macOS Keychain.
Fix options:
Option A: Update OAuth flow to write credentials to "Claude Code" instead of "Claude Code-credentials"
Option B: Update startup credential retrieval to read from "Claude Code-credentials" instead of "Claude Code"
Expected result: After running /login once, authentication should persist across all new terminal sessions without requiring the workaround or showing auth conflict warnings.
Error Messages/Logs
Debug logs showing Keychain lookup failure:
{"error":"Error: Command failed: security find-generic-password -a $USER -w -s \"Claude Code\"\nsecurity: SecKeychainSearchCopyNext: The specified item could not be found in the keychain."}
Terminal warning after applying workaround:
⚠️ Auth conflict: Both a token (claude.ai) and an API key (/login managed key) are set. This may lead to unexpected behavior.
• Trying to use claude.ai? claude /logout
• Trying to use /login managed key? claude /logout to sign out of claude.ai.
Keychain dump showing actual credential storage:
bash$ security dump-keychain | grep -i claude -A 5
0x00000007 <blob>="Claude Code-credentials"
0x00000008 <blob>=<NULL>
"acct"<blob>="rsargent"
"svce"<blob>="Claude Code-credentials"
Steps to Reproduce
1) Install Claude Code v2.0.14 (native installation)
2) Run claude
3) Execute /login command
4) Complete OAuth authentication in browser
5) Observe "Login successful" message
6) Exit Claude Code completely (exit or Ctrl+D)
7) Start a new Claude Code session: claude
8) Bug: See "Invalid API key - Please run /login" error
9) Verification: Run security find-generic-password -s "Claude Code" -w → fails
10) Verification: Run security find-generic-password -s "Claude Code-credentials" -w → succeeds (credentials exist)
Claude Model
Sonnet (default)
Is this a regression?
I don't know
Last Working Version
Unknown
Claude Code Version
v2.0.14
Platform
Anthropic API
Operating System
macOS
Terminal/Shell
Terminal.app (macOS)
Additional Information
Workaround (confirmed working):
bash# Run after every /login to sync credentials
CREDS=$(security find-generic-password -s "Claude Code-credentials" -w)
security add-generic-password -a "$USER" -s "Claude Code" -w "$CREDS"
Result: ✅ Authentication persists across sessions (warning shown but harmless)
Related Issues:
#5225 - Claude Code Login Authentication Not Persisting for Subscriber Users on remote SSH in MAC
#5244 - macOS OAuth authentication succeeds but auth token not persisted
#7358 - Claude Code SSH Authentication
#1222 - Authentication UI Warning Persists After Successful Login
Root Cause Analysis:
The inconsistency appears to be between:
Write path (OAuth flow): Uses service name "Claude Code-credentials"
Read path (Startup): Uses service name "Claude Code"
Both Keychain operations work correctly when using the proper service name, confirming this is purely a naming inconsistency rather than a permission or Keychain access issue.
Changelog Note:
v2.0.14 included "Reduce unnecessary logins" feature - this bug may be related to those authentication improvements.
11 Comments
Found 3 possible duplicate issues:
This issue will be automatically closed as a duplicate in 3 days.
🤖 Generated with Claude Code
In that terminal where Claude just started, first exit:
exit
Then run these commands in sequence:
# Step 1: Unlock keychain
security unlock-keychain ~/Library/Keychains/login.keychain-db
(Enter your Mac password when prompted)
# Step 2: Start Claude
claude
Then in the Claude session:
/login
Wait for "Login successful" (even though it will still show "Missing API key")
exit
# Step 3: Start Claude again
claude
Following the instructions from timyal above after removing the "Claude Code" entry, claude worked correctly and without warning at step 2 prior to doing a new /login.
A Claude Sonnet 4.5 instance which has been involved in the complete debugging process proposes that there is a problem with ACL permissions. Here is what it has to say on the matter:
CRITICAL FINDING - This is NOT a service name issue:
Timeline of what actually happened:
1) Previous /login created "Claude Code-credentials" entry with bad permissions
2) Claude Code startup couldn't read from it (permission denied)
3) Workaround: Copied data to "Claude Code" entry using security add-generic-password ✅ (worked because CLI tool uses permissive default ACLs)
4) Removed workaround to test
5) Ran security unlock-keychain ~/Library/Keychains/login.keychain-db
6) The ORIGINAL "Claude Code-credentials" entry immediately worked - BEFORE doing a new /login
Conclusion:
security unlock-keychain fixed the ACL permissions on the existing keychain entry. This proves:
❌ NOT a service name mismatch ("Claude Code" vs "Claude Code-credentials")
❌ NOT about creating a fresh credential
✅ OAuth-created keychain entries have restrictive ACL permissions
✅ security unlock-keychain resets/relaxes those permissions
✅ Command-line security add-generic-password creates entries with permissive ACLs (why workaround worked)
The bug: OAuth credential storage is setting incorrect Access Control Lists on the keychain item that prevent Claude Code from reading its own credentials.
Workaround for affected users:
bash
Question for maintainers: What API/method is used to write OAuth credentials to keychain? Can you verify the ACL permissions being set?
SSH/Remote Session Testing Update:
I tried the security unlock-keychain workaround in remote SSH sessions. Here are the findings:
✅ What Works
The workaround DOES work over SSH:
bash# Via Remote SSH terminal:
Key findings:
✅ Works in SSH/remote sessions
✅ Fixes credential access immediately
✅ No need to re-run /login - uses existing OAuth credentials
✅ Much faster than re-authenticating via browser
❌ What Doesn't Work
The unlock does NOT persist across SSH disconnections:
Test scenario:
Connected via VSCode Remote SSH
Ran security unlock-keychain - authentication worked ✅
Disconnected and reconnected VSCode Remote SSH
Started Claude Code - got "Invalid API key" error again ❌
Had to re-run security unlock-keychain to fix
Conclusion: The keychain unlock must be repeated for each new SSH connection. I do not know if other conditions, such as the mac sleeping, might also require repeating the keychain unlock during a given SSH session or not.
My auth tokens keep expiring every 2 days.
I had a similar "OAuth token revoked" issue but with a different root cause than the keychain mismatch described here. I'm not very tech-savvy, but worked through this with Claude and wanted to share what fixed it for me in case it helps others.
My symptoms: After running
/loginsuccessfully, I immediately got "OAuth token revoked" on the very first command.How this thread helped: The discussion about the "Auth conflict" warning in the comments was the key clue. When I saw that warning message specifically mention
CLAUDE_CODE_OAUTH_TOKENenvironment variable, it led us to check my shell config files.Root cause: I had an old OAuth token hardcoded in my
.zshrcfile:This was overriding the valid keychain credentials from
/login.Solution that worked:
Hope this helps anyone experiencing the same issue! The keychain workaround mentioned above didn't fix my problem, but removing this environment variable did.
This issue has been inactive for 30 days. If the issue is still occurring, please comment to let us know. Otherwise, this issue will be automatically closed in 30 days for housekeeping purposes.
Still an issue. I'm on macOS 15.7.1 (24G231)
This issue has been automatically closed due to 60 days of inactivity. If you're still experiencing this issue, please open a new issue with updated information.
This issue was closed incorrectly despite recent human comments. This behavior of the bot is reported at https://github.com/anthropics/claude-code/issues/16497. Please upvote that issue, so maybe it gets noticed.
This issue has been automatically locked since it was closed and has not had any activity for 7 days. If you're experiencing a similar issue, please file a new issue and reference this one if it's relevant.