Authentication UI Warning Persists After Successful Login
Bug Description Title: Claude Code CLI shows "Missing API key · Run /login" despite functional authentication
Description: While using Claude Code via SSH, I'm seeing a persistent message "Missing API key · Run /login" in the UI next to where I type messages. However, Claude Code is fully functional and responds to my queries correctly, suggesting that authentication is actually working properly.
Steps to reproduce:
- Start Claude Code via SSH
- Successfully authenticate via browser flow (copy URL to Safari, copy response code back)
- Successfully interact with Claude (messages are sent/received correctly)
- Notice the "Missing API key · Run /login" message remains visible in the UI
Expected behavior: Once successfully authenticated, the warning message should disappear.
Actual behavior: The warning message persists despite successful authentication and fully functional operation.
Environment details:
- Claude Code CLI: Latest version
- Operating system: macOS latest version
- Connection method: SSH from Prompt 3 on iPad to Mac via local WiFi tunnel
- Authentication method: Browser flow authentication (copy URL to Safari, copy response code back)
- Subscription: Claude Max plan
Additional information:
- Using Prompt 3 app on iPad to connect to Mac
- Both devices on same local WiFi network
- SSH tunnel established between iPad and Mac
- Fully functional despite the persistent error message
- The authentication flow completed successfully
Environment Info
- Platform: macos
- Terminal: ssh-session
- Version: 0.2.124
- Feedback ID: a5c6a2a6-3ec1-4d1b-a669-179a71cecdc5
Errors
[{"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.\n\n at genericNodeError (node:internal/errors:983:15)\n at wrappedFn (node:internal/errors:537:14)\n at checkExecSyncError (node:child_process:882:11)\n at execSync (node:child_process:954:15)\n at KW (file:///Users/ben/.nvm/versions/node/v22.12.0/lib/node_modules/@anthropic-ai/claude-code/cli.js:605:3513)\n at file:///Users/ben/.nvm/versions/node/v22.12.0/lib/node_modules/@anthropic-ai/claude-code/cli.js:535:15359\n at D (file:///Users/ben/.nvm/versions/node/v22.12.0/lib/node_modules/@anthropic-ai/claude-code/cli.js:493:13295)\n at aN1 (file:///Users/ben/.nvm/versions/node/v22.12.0/lib/node_modules/@anthropic-ai/claude-code/cli.js:535:14608)\n at qB (file:///Users/ben/.nvm/versions/node/v22.12.0/lib/node_modules/@anthropic-ai/claude-code/cli.js:535:14225)\n at $J1 (file:///Users/ben/.nvm/versions/node/v22.12.0/lib/node_modules/@anthropic-ai/claude-code/cli.js:1460:1005)","timestamp":"2025-05-21T11:52:14.944Z"},{"error":"Error: Could not resolve authentication method. Expected either apiKey or authToken to be set. Or for one of the \"X-Api-Key\" or \"Authorization\" headers to be explicitly omitted\n at file:///Users/ben/.nvm/versions/node/v22.12.0/lib/node_modules/@anthropic-ai/claude-code/cli.js:675:22923","timestamp":"2025-05-21T11:52:15.088Z"},{"error":"RangeError [ERR_CHILD_PROCESS_STDIO_MAXBUFFER]: stdout maxBuffer length exceeded\n at Socket.onChildStdout (node:child_process:481:14)\n at Socket.emit (node:events:524:28)\n at Socket.emit (node:domain:489:12)\n at addChunk (node:internal/streams/readable:561:12)\n at readableAddChunkPushByteMode (node:internal/streams/readable:512:3)\n at Readable.push (node:internal/streams/readable:392:5)\n at Pipe.onStreamRead (node:internal/stream_base_commons:189:23)","timestamp":"2025-05-21T11:52:15.790Z"},{"error":"Error: Command failed: security delete-generic-password -a $USER -s \"Claude Code\"\nsecurity: SecKeychainSearchCopyNext: The specified item could not be found in the keychain.\n\n at genericNodeError (node:internal/errors:983:15)\n at wrappedFn (node:internal/errors:537:14)\n at checkExecSyncError (node:child_process:882:11)\n at execSync (node:child_process:954:15)\n at KW (file:///Users/ben/.nvm/versions/node/v22.12.0/lib/node_modules/@anthropic-ai/claude-code/cli.js:605:3513)\n at eR0 (file:///Users/ben/.nvm/versions/node/v22.12.0/lib/node_modules/@anthropic-ai/claude-code/cli.js:535:16418)\n at tR0 (file:///Users/ben/.nvm/versions/node/v22.12.0/lib/node_modules/@anthropic-ai/claude-code/cli.js:535:16302)\n at li1 (file:///Users/ben/.nvm/versions/node/v22.12.0/lib/node_modules/@anthropic-ai/claude-code/cli.js:2035:2555)\n at ni1.startOAuthFlow (file:///Users/ben/.nvm/versions/node/v22.12.0/lib/node_modules/@anthropic-ai/claude-code/cli.js:2035:3744)\n at process.processTicksAndRejections (node:internal/process/task_queues:105:5)","timestamp":"2025-05-21T11:53:11.703Z"},{"error":"Error: Command failed: security find-generic-password -a $USER -w -s \"Claude Code\"\nsecurity: SecKeychainSearchCopyNext: The specified item could not be found in
Note: Error logs were truncated.
Hi there,
Thank you for the detailed and well-documented bug report! Your description of the issue is perfectly clear.
This is a known behavior when using applications that rely on the macOS Keychain over an SSH session. You are correct that the application is fully functional because you've successfully authenticated through the browser flow. The persistent "Missing API key" message is a UI bug stemming from how SSH sessions interact with the Keychain.
The Root Cause
When you log into your Mac graphically, your login.keychain is automatically unlocked. However, for security reasons, a new SSH session does not have access to this unlocked keychain. Therefore, while the core functionality of Claude Code works using a session token from your browser authentication, the UI component that checks for the stored API key in the keychain fails, causing the warning message to remain visible.
The Solution: Manually Unlock Keychain
To resolve this and make the warning message disappear, you can manually unlock your login keychain within your SSH session. Here are the steps:
-
Connect to your Mac via SSH as you normally do.
ssh your_username@your_mac_address -
After logging in, run the following command in your SSH terminal. This will unlock the keychain for your current session.
security unlock-keychain ~/Library/Keychains/login.keychain-db -
The terminal will prompt you for a password. Enter your Mac user login password (the same one you use to log into your computer).
After you enter the password, your keychain will be unlocked for the remainder of the SSH session. When you now start claude, it will be able to access the API key stored in the keychain, and the "Missing API key" warning should no longer be displayed.
For a More Permanent Fix (Optional)
If you SSH into this machine frequently, you can automate the unlock process by adding the command to your shell's startup script.
-
In your SSH session, open your shell's configuration file (e.g.,
~/.zshrcfor Zsh, or~/.bash_profilefor Bash).# For Zsh (default on modern macOS) nano ~/.zshrc -
Add the following lines to the end of the file. This script checks if you are in an SSH session and, if so, runs the unlock command.
if [ -n "$SSH_CONNECTION" ]; then security unlock-keychain ~/Library/Keychains/login.keychain-db fi -
Save the file and exit the editor.
Now, every time you start a new SSH session, you will be prompted for your keychain password right away, and all applications will have the access they need for the entire session.
Hope this helps clarify the issue and provides a solid workaround!
Updata:if [ -n "$SSH_CONNECTION" ]; then security unlock-keychain ~/Library/Keychains/login.keychain-db fi will import a new claude code bug
2. Add the following lines to the end of the file. This script checks if you are in an SSH session and, if so, runs the unlock command. if [ -n "$SSH_CONNECTION" ]; then security unlock-keychain ~/Library/Keychains/login.keychain-db fi
I use zsh. I added the above script to my .zprofile, so that it will only run in login shells.
Upon running Claude CLI I found that it is actually creating a login shell itself, which caused this to display:
It also seemed to cause problems with the CLI input; many of my keystrokes would not register.
So, I updated the script like this:
# Unlock Keychain on login
if [ -n "$SSH_CONNECTION" ] && [ -z "$KEYCHAIN_UNLOCKED" ]; then
security unlock-keychain ~/Library/Keychains/login.keychain-db
export KEYCHAIN_UNLOCKED=true
fi
So far this seems to have resolved the issue. I get asked to unlock the Keychain once when I SSH in, and Claude CLI is functioning normally again.
I'm a little concerned about whether the Keychain session will timeout, and where that will leave my active tmux sessions. I also don't think Claude should be running a login shell in principle - but I imagine they wanted to make sure all shell configuration is definitely loaded.
ETA: I have been using Claude Code over SSH to a Macbook Pro for almost a month (when I started using CC) without this keychain issue. It just popped up yesterday. Did they recently add code to have the CLI use the keychain? Personally I would like to be able to disable that via config to be able to avoid the above workaround.
@bcherny No update on this? I still have to unistall and install again every day.
Unlock Keychain on login
if [ -n "$SSH_CONNECTION" ] && [ -z "$KEYCHAIN_UNLOCKED" ]; then security unlock-keychain ~/Library/Keychains/login.keychain-db export KEYCHAIN_UNLOCKED=true fi
ETA: I have been using Claude Code over SSH to a Macbook Pro for almost a month (when I started using CC) without this keychain issue. It just popped up yesterday. Did they recently add code to have the CLI use the keychain? Personally I would like to be able to disable that via config to be able to avoid the above workaround.
Thanks man!
This probably bad in terms of security but saved me lot of time:
# use vs code (or derived) to put password into ~/.local/passwd, then add this block into your .zshrc
# may need less conditional check if you don't share .zshrc across multiple *nix systems
if [ -n "$SSH_CONNECTION" ] && [ -f "$HOME/.local/passwd" ] && [ -f "$HOME/Library/Keychains/login.keychain-db" ]; then
security unlock-keychain -p "$(cat ~/.local/passwd)" ~/Library/Keychains/login.keychain-db
fi
Any updates on this? the fixes above aren't working for me
2. Add the following lines to the end of the file. This script checks if you are in an SSH session and, if so, runs the unlock command. if [ -n "$SSH_CONNECTION" ]; then security unlock-keychain ~/Library/Keychains/login.keychain-db fiI use zsh. I added the above script to my
.zprofile, so that it will only run in login shells.Upon running Claude CLI I found that it is actually creating a login shell itself, which caused this to display:
It also seemed to cause problems with the CLI input; many of my keystrokes would not register.
So, I updated the script like this:
# Unlock Keychain on login if [ -n "$SSH_CONNECTION" ] && [ -z "$KEYCHAIN_UNLOCKED" ]; then security unlock-keychain ~/Library/Keychains/login.keychain-db export KEYCHAIN_UNLOCKED=true fiSo far this seems to have resolved the issue. I get asked to unlock the Keychain once when I SSH in, and Claude CLI is functioning normally again.
I'm a little concerned about whether the Keychain session will timeout, and where that will leave my active tmux sessions. I also don't think Claude should be running a login shell in principle - but I imagine they wanted to make sure all shell configuration is definitely loaded.
ETA: I have been using Claude Code over SSH to a Macbook Pro for almost a month (when I started using CC) without this keychain issue. It just popped up yesterday. Did they recently add code to have the CLI use the keychain? Personally I would like to be able to disable that via config to be able to avoid the above workaround.
This worked for me, thanks. I'm trying to get a iphone to mbp setup, only thing annoying about this is having to enter a password every time I open up my terminal app on my iphone (i know there's mosh, but it isn't working well for finger scroll atm but maybe need to put some time into configuring it).
Still encountering this after trying the many different solutions posted here in other issues.
Claude Code v1.0.84
I could not get any of the above workarounds to work.
I did finally after several hours end up with something that worked for me, however:
- Uninstalled all versions of claude (npm and native)
- Exit ssh, relogin to ssh
- security unlock-keychain ~/Library/Keychains/login.keychain-db
- npm install -g @anthropic-ai/[email protected]
- claude config set -g autoUpdates disable
- claude
- Do the /login flow (yea! it works!)
- run /migrate-installer inside claude (which also updates to latest)
- (this terminates claude after it is done)
- claude
Somehow this got my tokens in the right state and it works, even when I exit and ssh in again.
the solution here doesn't seem to work anymore
So this is as recent as yesterday, is there really no fix for this?
So this is as recent as yesterday, is there really no fix for this?
I fixed it by doing the thing above your comment, the Claude auto migrate thing along with the shell helper to unlock your keychain. Note that if you put in your keychain password wrong there is no error message.
I could not get any of the above workarounds to work.
I did finally after several hours end up with something that worked for me, however:
1. Uninstalled all versions of claude (npm and native) 2. Exit ssh, relogin to ssh 3. security unlock-keychain ~/Library/Keychains/login.keychain-db 4. npm install -g @anthropic-ai/[email protected] 5. claude config set -g autoUpdates disable 6. claude 7. Do the /login flow (yea! it works!) 8. run /migrate-installer inside claude (which also updates to latest) 9. (this terminates claude after it is done) 10. claudeSomehow this got my tokens in the right state and it works, even when I exit and ssh in again.
This worked for me.
It also seemed to cause problems with the CLI input; many of my keystrokes would not register.