[BUG] v2.0.14 macOS Keychain issue - OAuth authentication doesn't persist without security unlock-keychain each session

Status Closed — not planned
Maintainer reply None cached
Activity 11 comments · opened Oct 11, 2025 · closed Jan 21, 2026

[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.

View original on GitHub ↗

11 Comments

github-actions[bot] · 10 months ago

Found 3 possible duplicate issues:

  1. https://github.com/anthropics/claude-code/issues/1311
  2. https://github.com/anthropics/claude-code/issues/1470
  3. https://github.com/anthropics/claude-code/issues/1154

This issue will be automatically closed as a duplicate in 3 days.

  • If your issue is a duplicate, please close it and 👍 the existing issue instead
  • To prevent auto-closure, add a comment or 👎 this comment

🤖 Generated with Claude Code

timyal · 10 months ago

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

arwright · 10 months ago

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

security unlock-keychain ~/Library/Keychains/login.keychain-db
# Enter password - this fixes ACL permissions on existing credentials
# No need to re-login if credential already exists

Question for maintainers: What API/method is used to write OAuth credentials to keychain? Can you verify the ACL permissions being set?

arwright · 10 months ago

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:

security unlock-keychain ~/Library/Keychains/login.keychain-db
# Enter Mac password
# Claude Code authentication works immediately - no /login needed

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.

smolcompute · 10 months ago

My auth tokens keep expiring every 2 days.

matt-pare · 10 months ago

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 /login successfully, 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_TOKEN environment variable, it led us to check my shell config files.

Root cause: I had an old OAuth token hardcoded in my .zshrc file:

export CLAUDE_CODE_OAUTH_TOKEN=sk-ant-oat01-...

This was overriding the valid keychain credentials from /login.

Solution that worked:

  1. Check if you have this environment variable set:
   grep -r "CLAUDE_CODE_OAUTH_TOKEN" ~/.zshrc ~/.zprofile ~/.bash_profile ~/.bashrc
  1. If found, remove it:
   sed -i '' '/CLAUDE_CODE_OAUTH_TOKEN/d' ~/.zshrc
  1. Open a new terminal window and Claude Code should work properly now.

Hope this helps anyone experiencing the same issue! The keychain workaround mentioned above didn't fix my problem, but removing this environment variable did.

github-actions[bot] · 8 months ago

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.

pythoninthegrass · 8 months ago

Still an issue. I'm on macOS 15.7.1 (24G231)

github-actions[bot] · 7 months ago

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.

marcindulak · 7 months ago

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.

github-actions[bot] · 7 months ago

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.