anthropics / anthropics/claude-code
Windows: refresh-token rotation not persisted to .credentials.json; failed refresh blanks the store, locking out all fresh processes (2.1.220)
- Lingua principale
- Python
- Stelle
- 145k
- Fork
- 23.1k
- Metriche di merge delle PR
- Metriche PR in attesa
Descrizione
## Summary
On Windows, long-running interactive sessions stayed healthy for 40+ hours while the on-disk `%USERPROFILE%\.claude\.credentials.json` was never updated with rotated tokens - its `refreshTokenExpiresAt` remained at (last login + ~24h). When a fresh headless process (`claude --print` from a scheduled task, same user) started after that horizon, it failed auth AND the CLI rewrote `.credentials.json` with empty `accessToken`/`refreshToken`, leaving every subsequent fresh process unable to authenticate until a manual `claude auth login`.
## Environment
- Claude Code 2.1.220 (native install, `%USERPROFILE%\.local\bin\claude.exe`), autoUpdates disabled
- Windows 11 Pro (always-on desktop, no sleep/wake involved)
- Claude Max (20x) subscription, OAuth login (no API key, no keychain/Credential Manager entries - file store only)
- 2-3 concurrent interactive sessions typically running, plus one nightly headless `claude --print` scheduled task under the same user account
## Timeline (all times local, measured from file metadata and task logs)
1. Aug 31 ~16:49 - last interactive `claude auth login` on the machine.
2. Sep 1 16:49 - `refreshTokenExpiresAt` in `.credentials.json` (login + ~24h). Between login and this point the file was never rewritten, while multiple long-running sessions continued working (presumably refreshing in memory).
3. Sep 2 00:05:04 - `.credentials.json` mtime updates: `accessToken` and `refreshToken` now empty strings (`expiresAt: 0`), other fields (scopes, subscriptionType, `refreshTokenExpiresAt` from step 2) retained.
4. Sep 2 00:05:10 - the scheduled headless `claude --print` logs 401 on every model attempted.
5. Long-running interactive sessions from before the horizon continued working throughout (one ran 40+ hours total on the Aug 31 login).
## Questions
1. Is refresh-token rotation supposed to persist back to `.credentials.json` on Windows? Here the on-disk refresh token appears to have remained the original from login (horizon login+24h) while live sessions kept working, so any fresh process inherits a stale/superseded token.
2. Is rewriting the store with empty tokens on a failed refresh intended (defensive clear) or a bug? It converts one failed refresh into "every future process is locked out" with no visible error until the next launch.
3. `troubleshoot-install.md` documents a pre-v2.1.211 double-refresh/revocation race ("Parallel sessions... coordinate its renewal so that only one process refreshes"). This machine is on 2.1.220 - is the coordination expected to cover a scheduled-task process starting fresh at a fixed time?
## Workaround in place
The scheduled task now authenticates via a `claude setup-token` one-year token injected as `CLAUDE_CODE_OAUTH_TOKEN` at runtime, which works well (and is a great facility) - filing this because the interactive-store behavior seems like it will bite anyone running scheduled headless work off a shared login.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Guida per i contributori
Nessuna guida per i contributori indicizzata per questo repository
Direzione di ricerca
Start by reproducing the Windows flow with concurrent interactive sessions and a scheduled `claude --print`, inspecting `%USERPROFILE%\.claude\.credentials.json` before and after token refresh and failed refresh. Compare the behavior with the coordination guidance in `troubleshoot-install.md`; done means rotated credentials persist safely and a failed refresh does not blank the shared store or leaves clear recovery behavior.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Valutazione
- Ambito
- authentication, cli
- Tipo di issue
- Bug
- Difficoltà
- 4/5
- Tempo stimato
- 3-5 giorni
- Stato di attività
- Attiva
- Chiarezza
- Da chiarire
- Idoneità per principianti
- 35/100