Skip to content

Refresh limit token cache doesn't re-read Keychain when the previous token is still valid (stale account after switching) #300

Closed

Description

@edoproch

Environment

  • PokeTokenBar 2.5.4
  • macOS 26.6 (25G72), Apple Silicon
  • Keychain-only install (no ~/.claude/.credentials.json)
  • Claude Code, Team plan, switching between two email accounts on the same Team

Problem

After switching Claude Code accounts via /logout → /login (same Team, two emails), the official
5h/weekly limits in PokeTokenBar keep showing the previous account indefinitely, even after
repeatedly pressing Settings → Refresh limit token cache.

  • Popover keeps showing Account: edoardo@memoraiz after switching to hello@memoraiz.
  • fiveHour/sevenDay stay frozen for many refresh cycles while the local token counter (feeding
    companion EXP) keeps climbing normally — the two data paths clearly disagree.

Root cause (traced in OAuthLimitsProvider.swift)

UsageStore.refreshLimitTokenFromKeychain() calls limitsProvider.fetch(allowKeychainPrompt: true),
which calls OAuthAccessTokenCache.accessToken(allowKeychainPrompt: true) — with the default
bypassCache: false:

if !bypassCache, let cachedCredential, !cachedCredential.isExpired {
    return cachedCredential.accessToken
}

cachedCredential is only cleared by invalidate(), called only from the 401/403 retry path. A
second, independently-valid Team account's token never gets a 401/403 from api.anthropic.com, so
it's returned from memory forever — Keychain is never queried again after the first successful read,
no matter how many times the refresh button is pressed.

This also makes the log misleading: UsageStore.swift logs "limits refreshed from keychain by user action" unconditionally on success, even when the token actually came from the in-memory cache and
Keychain was never touched. My own log shows exactly this pattern for hours after switching accounts.

Different bug from #227/#228 (fixed the .credentials.json file path) and #232 (fixed picking the
right entry among multiple Keychain items) — this install has no credentials file, and presumably
one relevant Keychain item, so neither prior fix applies here.

Steps to reproduce

  1. Keychain-only install. Sign into Claude Code as Account A (Team). Press Refresh limit token
    cache
    once so the popover shows Account A.
  2. /logout, then /login as Account B (different email, same Team, so Account A's token stays
    valid server-side).
  3. Press Refresh limit token cache again (any number of times).

Expected: limits and account label switch to Account B.
Actual: limits and account label stay on Account A indefinitely.

Suggested fix

Have the explicit user-action path force bypassCache: true — it's already an intentional user
action, same category as the existing 401/403-triggered bypass retry, so there's no
privacy/prompt-avoidance reason to prefer the cache here.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions