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

Resolved 💬 2 comments Opened Jun 28, 2026 by brks-rssll 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 ↗

This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗