fix(services): identify accounts by accountUuid, not rotating refresh token#264
Open
AlvaroTena wants to merge 1 commit into
Open
fix(services): identify accounts by accountUuid, not rotating refresh token#264AlvaroTena wants to merge 1 commit into
AlvaroTena wants to merge 1 commit into
Conversation
… token resyncBeforeSwitching used the OAuth refreshToken as an account-identity check. Claude Code rotates the refreshToken on every token refresh within the same account, so the guard treated legitimate same-account switches as 'different account' and skipped the re-sync. The profile's stored credentials froze at a now-invalidated token (and the live rotated one was discarded), which later broke profile switching with HTTP 401. Identify accounts by the stable oauthAccount.accountUuid instead, only skipping the re-sync when account ids genuinely differ. Fall back to the legacy refreshToken comparison when an account id is unavailable on either side. Fixes hamed-elfayome#263
chenwei791129
added a commit
to chenwei791129/Claude-Usage-Tracker
that referenced
this pull request
Jul 1, 2026
…ntUuid identity)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #263
Problem
resyncBeforeSwitchingused the OAuthrefreshTokenas an account-identity check (guard added in #215 to prevent cross-profile contamination). But Claude Code rotates therefreshTokenon every token refresh within the same account, sofresh != storedis almost always true even for the same account. The guard therefore skipped the re-sync on essentially every switch, leaving the profile's stored credentials frozen at a now-invalidated token (and discarding the live rotated one). Once the stored access token expired, switching to that profile wrote dead credentials to the keychain →401 Invalid authentication credentials→ forcedclaude /login.See #263 for the full root-cause analysis and a controlled A/B experiment reproducing both the failure and this fix.
Change
Identify accounts by the stable
oauthAccount.accountUuid(already captured per-profile inoauthAccountJSONsince #175) instead of the rotating refresh token. The re-sync is skipped only when account ids genuinely differ. When an account id is unavailable on either side, it falls back to the legacy refresh-token comparison, so behavior is unchanged for profiles that predateoauthAccountJSONcapture.accountUUID(fromOAuthAccountJSON:).resyncBeforeSwitchingguard reworked to use account identity with a refresh-token fallback.This is intentionally scoped to the primary fix (bug 1). The defense-in-depth follow-up discussed in #263 (refusing to write already-expired credentials over a working keychain in
applyProfileCredentials) is left out of this PR to keep it focused.Testing
xcodebuild ... -scheme "Claude Usage" build→ BUILD SUCCEEDED (Xcode 26.5).A → Band switching profiles, the stored profile token stayed at the deadA(rotation discarded).Y → Z; the stored profile token correctly becameZ(rotation captured). No re-login required.Notes
~/.claudesetups: refresh-token identity guard rots stored credentials, thenapplyProfileCredentialswrites dead tokens (401) #263 in case they can be addressed together.