OAuth refresh token never used — forces re-login every 8 hours
Description
Claude Code CLI stores both an accessToken and refreshToken in the macOS Keychain (Claude Code-credentials), but the refresh token is never used. When the 8-hour access token expires, the CLI invalidates the cached credentials instead of refreshing, forcing the user to /login again.
Steps to Reproduce
/loginto authenticate (creates keychain entry withaccessToken+refreshToken)- Keep a session running (interactive or via
-cresume) for longer than 8 hours - Background
client_datapoll toapi.anthropic.com/api/oauth/claude_cli/client_datareturns HTTP 401: "OAuth token has expired" - Next user prompt fails with "Could not resolve authentication method"
- User must
/loginagain
Evidence
Observed 5 times across versions 2.1.62–2.1.69. The pattern is consistent:
| Login (UTC) | Next 401 (UTC) | Apparent Lifetime |
|---|---|---|
| Feb 22 05:26 | Feb 27 21:36 | ~5.7 days (machine sleeping) |
| Feb 27 22:27 | Feb 28 06:51 | ~8.4 hours |
| Feb 28 14:21 | Mar 02 06:46 | ~1.7 days (machine sleeping) |
| Mar 03 02:32 | Mar 05 08:59 | ~2.3 days (machine sleeping) |
The access token's expiresAt field confirms an 8-hour lifetime. Longer apparent lifetimes are due to the machine being asleep (no poll = no 401 detection).
Debug logs show zero refresh activity — the word "refresh" only appears in the 401 error message itself. The [API:auth] OAuth token check path appears to only validate the access token's presence, not trigger a refresh flow.
Additionally, every /login logs Error: Failed to delete keychain entry (non-fatal) before auth_success, suggesting the token was already cleared by the invalidation step.
Expected Behavior
When the client_data poll receives a 401, the CLI should use the stored refresh token to obtain a new access token transparently, without requiring user interaction.
Workaround
Short-lived claude -p invocations (e.g., from automation scripts) are unaffected because each process reads the current keychain credentials at startup. Only long-running interactive sessions or -c resumed sessions hit this bug.
Environment
- macOS 15 (Darwin 25.3.0)
- Claude Code 2.1.69 (also reproduced on 2.1.62–2.1.68)
- Anthropic Max subscription
- Auth method: OAuth (not API key)
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗