Stale OAuth refresh token causes persistent 401 "Invalid authentication credentials" that `/login` does not recover from (manual deletion of ~/.claude/.credentials.json required)

Resolved 💬 2 comments Opened Jun 6, 2026 by tanaeakihiko Closed Jun 6, 2026

What happened

After ~2 months of using Claude Code without an interactive re-login, every request started failing with:

API Error: 401 Invalid authentication credentials

Running /login printed "Login successful", but requests kept returning the same 401. The only thing that fixed it was manually deleting the credentials file and logging in again:

rm ~/.claude/.credentials.json
# then /login

After deletion, /login performed a fresh browser OAuth grant and authentication worked normally again.

Why I think this happens

The credentials file (~/.claude/.credentials.json) stores claudeAiOauth with accessToken, refreshToken, and expiresAt. My access token had been silently refreshed for ~55 days without a full interactive login, so only expiresAt was being updated while the original grant's refreshToken aged.

When the refreshToken itself expired / was rotated server-side, the refresh attempt failed and produced the 401. Crucially, /login appears to reuse / refresh the existing token entry rather than forcing a clean new grant, so the stale refreshToken kept being used and the 401 persisted despite "Login successful". Deleting the file removed the stale state and forced a full re-authorization, which is why it recovered.

(I confirmed locally that this was not an ANTHROPIC_API_KEY conflict — no such env var was set — and not a scope/format change, since both the original and current logins were on the same 2.1.x series.)

Expected behavior

  • /login should always perform a clean grant and fully overwrite existing tokens, instead of attempting to reuse/refresh a possibly-stale entry.
  • If a token refresh fails with 401, Claude Code should automatically discard the stale credentials and fall back to a full re-authorization (i.e. do internally what rm ~/.claude/.credentials.json does manually).
  • A 401 Invalid authentication credentials should surface an actionable message such as "Your saved credentials are no longer valid — run /login to re-authenticate", rather than leaving the user in the confusing "Login successful but still 401" state.

Steps to reproduce

  1. Log in via /login (OAuth / Claude subscription).
  2. Use Claude Code over a long period (weeks) so the access token is only ever refreshed, never re-granted via interactive login.
  3. Once the underlying refreshToken expires / is rotated, requests fail with 401.
  4. Run /login — it reports success but requests still 401.
  5. Delete ~/.claude/.credentials.json and /login again — works.

Environment

  • Claude Code: 2.1.165 (native install)
  • OS: Linux (WSL2, Ubuntu)
  • Auth: OAuth (Claude Max subscription)
  • Original interactive login: ~2 months prior, on 2.1.104; refresh-only usage since.

View original on GitHub ↗

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