diff --git a/05-troubleshooting/claude-code-keychain-prompt-recurring-macos.md b/05-troubleshooting/claude-code-keychain-prompt-recurring-macos.md new file mode 100644 index 0000000..dc7511e --- /dev/null +++ b/05-troubleshooting/claude-code-keychain-prompt-recurring-macos.md @@ -0,0 +1,73 @@ +--- +title: "Claude Code Keychain Prompt Keeps Reappearing on macOS (ACL Invalidation)" +domain: troubleshooting +category: claude-code +tags: [claude-code, authentication, oauth, keychain, macos, acl, security] +status: published +created: 2026-06-15 +updated: 2026-06-15 +--- + +# Claude Code Keychain Prompt Keeps Reappearing on macOS (ACL Invalidation) + +## Symptom +A macOS dialog repeatedly pops up: + +> **security wants to access key "Claude Code-credentials" in your keychain.** +> To allow this, enter the "login" keychain password. — `[Always Allow] [Deny] [Allow]` + +The tell-tale sign: it **comes back even after clicking "Always Allow"** — the usual "trust forever" button doesn't make it stop. Login still works; it's the *permission prompt* that won't quiet down. This is **distinct** from [Claude Code won't log in](claude-code-warp-login-corrupt-keychain-credential.md), where the stored credential is corrupt and login itself fails. + +## Cause +Claude Code stores its OAuth token in the macOS **login keychain** as `Claude Code-credentials`, read via `/usr/bin/security`. macOS binds an "Always Allow" grant (the keychain item's ACL) to the **code-signing identity** of the requesting binary. That grant is silently invalidated when: + +- **Claude Code updates** — the new binary's signature no longer matches the saved ACL. This is the most common trigger (see claude-code issues #48162, #9403). +- **The credential item is recreated on token refresh** — wipes the ACL. +- **Post-reboot keychain churn** — right after boot, the just-unlocked login keychain plus a concurrent token refresh can race ahead of the ACL settling, producing a *burst* of prompts that stops once a clean refresh completes. + +It is **not** a lock-timeout issue if `security show-keychain-info` reports `no-timeout` (below). + +## Triage (non-destructive — these do not trigger a prompt) +```bash +# Confirm the item exists (metadata only; no secret read) +security find-generic-password -l "Claude Code-credentials" | grep -E "svce|acct" + +# Confirm the login keychain isn't auto-locking +security show-keychain-info ~/Library/Keychains/login.keychain-db +# -> "no-timeout" means it won't relock; so recurring prompts = ACL invalidation, not locking +``` + +## Fixes + +### One-off burst (e.g. right after a reboot) +Click **Always Allow** (not Allow) once a clean token refresh has completed. With a `no-timeout` keychain the grant then holds, and the post-boot prompt storm usually self-clears within a minute. *Observed exactly this on MajorAir 2026-06-15 — a reboot triggered a burst that stopped on its own.* + +### Keeps returning after updates (durable) — reset the credential +Deleting and re-creating the item rebinds a fresh ACL to the current binary. Costs one re-login. +```bash +security delete-generic-password -s "Claude Code-credentials" +# then re-authenticate inside Claude Code: /login (or relaunch `claude`) +``` + +### Bypass the keychain entirely (workaround) +Claude Code falls back to `~/.claude/.credentials.json` in non-GUI contexts (SSH, tmux). On a local Mac this can be repurposed to stop keychain prompts for good: +```bash +# pipe straight to the file — never echo the token into a shared terminal +security find-generic-password -s "Claude Code-credentials" -w > ~/.claude/.credentials.json +chmod 600 ~/.claude/.credentials.json +security delete-generic-password -s "Claude Code-credentials" +``` +**Caveats:** +- Token is then **plaintext at rest** (mode 600) instead of encrypted in the keychain. +- A future Claude Code update may rewrite the keychain item. +- GUI-session behaviour for the file fallback is **less documented** than the SSH/tmux case — **verify it holds for your setup before relying on it.** +- Do **not** substitute `CLAUDE_CODE_OAUTH_TOKEN` — it is known to delete credentials on exit (issue #37512). + +## Notes +- Same keychain item as the corrupt-credential login failure; if login itself breaks, see the related article. +- Always redirect `-w` output straight to a file — never into a terminal whose scrollback feeds shared context. + +## Related +- [Claude Code Won't Log In (Warp & iTerm2) — Corrupt Keychain Credential](claude-code-warp-login-corrupt-keychain-credential.md) +- Config: `~/.claude.json`, login keychain item `Claude Code-credentials` +- First observed: MajorAir, 2026-06-15 (post-reboot prompt burst; self-cleared) diff --git a/05-troubleshooting/claude-code-warp-login-corrupt-keychain-credential.md b/05-troubleshooting/claude-code-warp-login-corrupt-keychain-credential.md index 9f60b99..740c9a7 100644 --- a/05-troubleshooting/claude-code-warp-login-corrupt-keychain-credential.md +++ b/05-troubleshooting/claude-code-warp-login-corrupt-keychain-credential.md @@ -61,5 +61,6 @@ Resolved on step 1+2 — login succeeded after deleting the corrupt Keychain ite If that errors with "Expecting value", the stored secret is empty/corrupt — delete and re-login. ## Related +- [Claude Code Keychain Prompt Keeps Reappearing on macOS (ACL Invalidation)](claude-code-keychain-prompt-recurring-macos.md) — different symptom: login works but the permission prompt won't stop - Config: `~/.claude.json` (oauthAccount, userID), login Keychain item `Claude Code-credentials` - Other Claude Code note: `claude-mem-setting-sources-empty-arg.md` diff --git a/05-troubleshooting/index.md b/05-troubleshooting/index.md index e6a013f..489999b 100644 --- a/05-troubleshooting/index.md +++ b/05-troubleshooting/index.md @@ -60,3 +60,4 @@ Practical fixes for common Linux, networking, and application problems. - [Windows OpenSSH Server (sshd) Stops After Reboot](networking/windows-sshd-stops-after-reboot.md) - [claude-mem Silently Fails with Claude Code 2.1+ (Empty `--setting-sources`)](claude-mem-setting-sources-empty-arg.md) - [Claude Code Won't Log In (Warp & iTerm2) — Corrupt Keychain Credential](claude-code-warp-login-corrupt-keychain-credential.md) +- [Claude Code Keychain Prompt Keeps Reappearing on macOS (ACL Invalidation)](claude-code-keychain-prompt-recurring-macos.md) diff --git a/SUMMARY.md b/SUMMARY.md index 2e4d9ee..6014b65 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -117,6 +117,7 @@ updated: 2026-05-15T09:00 * [Ollama Drops Off Tailscale When Mac Sleeps](05-troubleshooting/ollama-macos-sleep-tailscale-disconnect.md) * [Ollama: `ollama run` with Piped Stdin Bypasses Chat Template + SYSTEM Prompt](05-troubleshooting/ollama-chat-template-pipe-stdin-bypass.md) * [Claude Code Won't Log In (Warp & iTerm2) — Corrupt Keychain Credential](05-troubleshooting/claude-code-warp-login-corrupt-keychain-credential.md) + * [Claude Code Keychain Prompt Keeps Reappearing on macOS (ACL Invalidation)](05-troubleshooting/claude-code-keychain-prompt-recurring-macos.md) * [iPhone Mirroring Hangs on 'Connecting…' — AWDL Data Stall (27.0 Beta)](05-troubleshooting/iphone-mirroring-connecting-hang-awdl-stall-beta.md) * [rsync over Tailscale: Hung in TCP Teardown After Transfer Completes](05-troubleshooting/networking/rsync-tailscale-teardown-stall.md) * [iOS Tailscale Clients Report HostName="localhost" — Breaks /etc/hosts Generators](05-troubleshooting/networking/tailscale-status-json-hostname-localhost-ios.md)