Single failed proactive token refresh hard-wipes auth and traps every session in an uncompletable /login

Status Fixed / completed
Reported on v2.1.195
Maintainer reply None cached
Activity 4 comments · opened Jun 28, 2026 · closed Jun 28, 2026

A single failed proactive token refresh hard-wipes auth and traps every session in an uncompletable /login

Environment

  • Claude Code: 2.1.195 (npm-global, @anthropic-ai/claude-code)
  • OS: macOS (Darwin 25.5.0), Apple Silicon
  • Auth: claude.ai subscription (OAuth), no ANTHROPIC_API_KEY
  • Credential store: macOS Keychain (Claude Code-credentials)
  • Multiple concurrent Claude Code clients on one machine sharing the single OAuth credential: the desktop app, the headless claude.exe daemon, several background/forked sessions, and terminal claude.

Summary

After ~2 weeks of flawless automatic token refreshes, one scheduled proactive refresh failed. Instead of falling back to the still-valid keychain token, the daemon discarded the token entirely (no token found), and from that instant every session — including brand-new ones — demanded /login. The /login flow is itself unusable in the TUI, so there was no in-TUI way to recover.

There are really two bugs here:

Bug 1 — one failed proactive refresh hard-discards auth for all sessions

From ~/.claude/daemon.log, the refresh ran cleanly every ~8h for two weeks, then failed exactly once and nuked the token:

[2026-06-14T19:59:16Z] [supervisor] auth: proactive refresh succeeded
...  (≈30 consecutive successes, every ~8h, through Jun 27) ...
[2026-06-27T02:32:31Z] [supervisor] auth: proactive refresh succeeded      <- last good
[2026-06-28T02:18:54.730Z] [supervisor] auth: proactive refresh starting
[2026-06-28T02:18:54.786Z] [supervisor] auth: proactive refresh failed, signalling re-auth required
[2026-06-28T02:18:54.791Z] [supervisor] auth: headless daemon cannot complete OAuth — run `claude auth login` to refresh
[2026-06-28T02:18:54.791Z] [supervisor] auth: no token found, will re-check keychain every 30s

Every /login prompt across all sessions dates from that 02:18:54Z event. A single transient/revoked refresh should not wipe auth and lock all sessions — it should fall back to the unexpired keychain access token and/or retry, not declare no token found.

Likely trigger: the refresh token was revoked server-side. This lines up with a Pro→Max subscription upgrade (and/or signing in again on web/desktop) shortly before — changing subscription appears to revoke existing OAuth refresh tokens, so the daemon's next routine refresh failed. Earlier log lines also show multiple processes refreshing the same credential cross-process (token still valid (cross-process refresh or not yet due)), so shared-credential rotation may compound this.

Bug 2 — the TUI /login flow is unusable, so there is no recovery path inside the TUI

When dropped into /login:

  • The login URL does not auto-open a browser, even though $BROWSER is empty (so it should fall back to open) and open https://anthropic.com works fine from the same shell.
  • The c "copy URL" shortcut does not place the URL on the clipboard (nothing copied).
  • The full-screen TUI has mouse reporting on, so normal click-drag selection of the URL is swallowed by the app — can't manually select + ⌘C either.

Net effect: the URL is visible on screen but there is no working path to follow it, so login cannot be completed from within the TUI. (Workaround that does work: claude auth login as a plain CLI command outside the TUI.)

Symptoms observed

  • New, post-upgrade sessions: typing any message returns Not logged in · Please run /login.
  • claude auth status simultaneously reports { "loggedIn": true, "subscriptionType": "max" } and the keychain holds a non-expired access token — i.e. a valid token exists, yet inference is rejected and the daemon reports no token found.
  • Resuming any session that was open across the 02:18 event always re-throws /login and can never be revived for sending (its content is still readable on disk).

Steps to reproduce

  1. Run Claude Code (subscription/OAuth) with the background daemon and one or more other clients (desktop app, extra CLI sessions) sharing the keychain credential.
  2. Change the subscription tier (e.g. Pro→Max) and/or sign in again on another Claude surface, revoking the existing refresh token.
  3. Wait for the daemon's next scheduled proactive refresh.
  4. Observe: refresh fails → no token found → all sessions (including new ones) demand /login.
  5. In the TUI /login: the URL neither auto-opens nor copies; login cannot be completed.

Expected

  • A failed proactive refresh should retry and/or fall back to the still-valid keychain access token, not discard auth for every session.
  • A subscription change should not silently brick existing CLI sessions; if the refresh token is revoked, re-auth should be needed once and recover cleanly, not trap sessions.
  • The TUI /login URL must be openable (honor open/$BROWSER) and copyable; with mouse reporting on, provide a reliable copy affordance.

Actual

All sessions stuck on /login with a valid token present; the TUI /login is a dead end; the only recovery was claude auth logout && claude auth login from a plain shell. Sessions that were live across the event are permanently unresumable for sending.

Workaround

claude auth logout
claude auth login --claudeai     # plain CLI; URL prints as normal text and auto-opens via `open`
claude auth status               # confirm loggedIn:true + correct subscriptionType

Then fully quit lingering clients (incl. the headless claude.exe daemon, which respawns) so they re-read the fresh keychain token; start a new session (old ones remain unresumable).

View original on GitHub ↗

4 Comments

github-actions[bot] · 3 months ago

Found 3 possible duplicate issues:

  1. https://github.com/anthropics/claude-code/issues/71757
  2. https://github.com/anthropics/claude-code/issues/29896
  3. https://github.com/anthropics/claude-code/issues/65761

This issue will be automatically closed as a duplicate in 3 days.

  • If your issue is a duplicate, please close it and 👍 the existing issue instead
  • To prevent auto-closure, add a comment or 👎 this comment

🤖 Generated with Claude Code

yurukusa · 3 months ago

Good root-cause — the fail-closed discard (drop the token instead of falling back to the still-valid keychain entry) is the real Bug 1. A few things that help recover and reduce blast radius while that's fixed:
Recover without the wedged in-TUI /login: the OAuth flow works from a plain terminal even when the in-session /login is stuck. Quit every running client first (so nothing is racing on the credential), then from a fresh shell run the login flow outside any session — the daemon's own log points at this (run claude auth login). Completing the browser OAuth there re-seats the credential for all clients; you don't have to fight the TUI prompt.
Before re-login, check whether the keychain entry actually survived: on macOS,

security find-generic-password -s "Claude Code-credentials" -w

If a token is still there, the daemon only dropped its in-memory copy and a clean restart of the clients may be enough (no full re-auth). If it returns nothing, the entry was nuked and you do need the re-login above. Either way this tells you which failure you're in instead of guessing.
Your conversations are not lost. The auth wipe traps sessions but does not touch transcripts — they live on disk under ~/.claude/projects/<encoded-cwd>/…. After you re-auth, claude --resume (or -r) lists and reopens them, so nothing you were working on is gone. Worth saying because "every session demands /login" reads like data loss, and here it genuinely isn't.
Reduce the blast radius: the amplifier is several clients (desktop, claude.exe daemon, forks, terminal) all proactively refreshing one shared OAuth credential — so a single refresh failure nukes auth for all of them at once. Until the keychain-fallback fix lands, having fewer clients own the proactive refresh (ideally one) shrinks the single-point-of-failure window. For purely headless/daemon use, an ANTHROPIC_API_KEY-based credential sidesteps the OAuth refresh race entirely — though that's a separate billing path from your claude.ai subscription, so it's a trade-off, not a free fix.
The core fix is still yours to make on the client side: a failed proactive refresh should re-read the keychain and keep serving the valid token, never hard-discard and fail-closed across every session.

brks-rssll · 3 months ago

Closing as a duplicate of #71757 (the failed-refresh auth-wipe). I've added this machine's daemon-log evidence there. The separate TUI /login URL-UX problem from this report is split out into https://github.com/anthropics/claude-code/issues/72008.

github-actions[bot] · 1 month ago

This issue has been automatically locked since it was closed and has not had any activity for 7 days. If you're experiencing a similar issue, please file a new issue and reference this one if it's relevant.