Skip to content

fix(menubar): stop repeated keychain prompts on token refresh (#490)#491

Merged
iamtoruk merged 1 commit into
mainfrom
fix/menubar-keychain-prompt-490
Jun 14, 2026
Merged

fix(menubar): stop repeated keychain prompts on token refresh (#490)#491
iamtoruk merged 1 commit into
mainfrom
fix/menubar-keychain-prompt-490

Conversation

@iamtoruk

Copy link
Copy Markdown
Member

Fixes #490.

Problem

The menubar re-reads the Claude Code-credentials keychain item on every silent token refresh (proactive near-expiry refresh and post-401 retry) via the Security framework. On macOS Sierra+, access to a generic-password item is governed by its partition list, not the legacy "Always Allow" ACL shown in Keychain Access. Claude Code resets that partition list each time it rotates its OAuth credential, which drops the menubar's code identity from the allowed set. The next read then raises a fresh keychain password prompt. On a heavy Claude Code day this fires dozens of times.

The LAContext.interactionNotAllowed flag the code relied on does not suppress the partition-list prompt for a plain generic-password item, so the "silent" path was not actually silent.

Fix

Route the silent read path through /usr/bin/security find-generic-password ... -w. The Apple-signed security binary sits in the item's apple-tool: partition, so it reads the secret without ever prompting and without depending on the user's ACL grant. It is read-only and never spends the shared refresh token, so the existing invariant (the Claude CLI owns the grant; we never refresh it ourselves) is preserved.

The user-initiated bootstrap keeps the framework read, where a single consent prompt is expected. Removes the now-unused LocalAuthentication import and the ineffective interactionNotAllowed branch.

Did not implement the issue's suggested Option A (refresh via the Anthropic OAuth API using the cached refresh token): Claude's refresh token is single-use and shared with the CLI, so spending it would invalidate the user's claude login. Option B (this change) avoids that.

Scope

Menubar app only (mac/Sources/CodeBurnMenubar/). No CLI changes.

Verification

  • swift build passes.
  • Confirmed security find-generic-password -s "Claude Code-credentials" -a "$USER" -w returns the valid claudeAiOauth JSON with no prompt on macOS.
  • Not reproduced end to end: the original symptom requires Claude Code rotating its credential and resetting the partition list over hours of use.

Release

Ship as mac-v0.9.13 (not a re-upload of 0.9.12): the in-app updater only offers an update when the release version is strictly greater than the installed version, so reusing 0.9.12 would never reach existing users.

…#490)

Background token refreshes re-read the "Claude Code-credentials" keychain
item via the Security framework. On macOS Sierra+, access is governed by the
item's partition list, not the legacy "Always Allow" ACL. Claude Code resets
that partition list every time it rotates the credential, dropping our app
from the allowed set, so the next read raises a fresh keychain password
prompt. On a heavy usage day this fires dozens of times. The LAContext
interactionNotAllowed flag we relied on does not suppress that prompt for a
plain generic-password item.

Route the silent path (proactive refresh and post-401 re-read) through
/usr/bin/security instead. The Apple-signed security binary sits in the
item's apple-tool: partition, so it reads the secret without prompting and
without depending on the user's ACL grant. It is read-only and never spends
the shared refresh token, preserving the existing invariant that the Claude
CLI owns the grant.

The user-initiated bootstrap keeps the framework read, where a single
consent prompt is expected. Drops the now-unused LocalAuthentication import.
@iamtoruk iamtoruk merged commit 694e8ce into main Jun 14, 2026
3 checks passed
@iamtoruk iamtoruk deleted the fix/menubar-keychain-prompt-490 branch June 14, 2026 08:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Repeated macOS keychain password prompts despite "Always Allow"

1 participant