fix(credentials): Use an authenticated Claude probe to refresh tokens - #25
Conversation
The Claude refresh candidates only read local state, so neither could refresh an expired token in ~/.claude/.credentials.json. "auth status" prints the stored auth state and exits, despite a comment claiming it probes Anthropic auth servers, and "--version" never touches auth at all. When the token expired, EnsureTokenReady ran a refresh that could not succeed and the provider stayed degraded. Running each candidate against an expired access token paired with an invalid refresh token shows which ones attempt a refresh: "auth status", "--version" and "agents --json" leave the token untouched, while "doctor" and "mcp list" both try. Use "doctor" as the primary probe, since it resolves the account and completes quickly, and keep "mcp list" as a fallback. The candidate test now also rejects the three commands proven inert, so a future edit cannot quietly reintroduce a probe that never refreshes. Refs #24
|
Warning Review limit reachedYou’ve reached a temporary PR review limit under our Fair Usage Limits Policy. Next review available in: 2 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
Comment |
Summary
limitscould not refresh an expired Claude token, because both refresh candidates only read local state.claude auth statusprints the stored auth state and exits, despite a code comment claiming it "probes Anthropic auth servers and forces Claude Code CLI to refresh expired OAuth tokens", andclaude --versionnever touches auth at all. When the token in~/.claude/.credentials.jsonexpired,EnsureTokenReadyran a refresh that could not succeed and the provider stayed degraded until the user happened to run Claude Code interactively.This is the same class of bug as #23, where
grok --versionwas replaced with an authenticatedgrok modelsprobe. This change gives Claude the same treatment: probe with a command that actually resolves the account, so the CLI refreshes the token as a side effect.Each candidate was run against a home directory holding an expired access token paired with a deliberately invalid refresh token, then the credentials file was checked for a refresh attempt:
claude auth statusclaude --versionclaude agents --jsonclaude doctorclaude mcp listdoctoris the primary probe, as it resolves the account and completes in about a second.mcp listis the fallback.Fixes #24
Changes
pkg/credentials/credentials.goauth statusand--versionwithdoctorandmcp list.pkg/credentials/credentials_test.goTestGetCliCandidatesClaudenow requires a real refresh probe and rejects the three commands proven inert, so a future edit cannot quietly reintroduce a probe that never refreshes.TestForceRefreshViaCliHeadlessCandidateValidation's fake CLI to model the new candidate pair:doctorruns without refreshing,mcp listwrites a fresh token. The call-log assertion still proves both candidates ran, in order.Test plan
All pass locally.
Verify the new test catches the old bug, by reverting only the source change:
Manual verification against a real account:
go build -o dist/limits . ./dist/limits --no-color -p claudeReports the session and weekly windows with no degraded state.
Note: CI cannot run on this repository at the moment. GitHub Actions reports "The job was not started because recent account payments have failed or your spending limit needs to be increased", which is also why the checks on #23 showed red. The verification above was therefore run locally.