[Bug] Exit-time refresh tokens not persisted, causing invalid grant errors on restart

Resolved 💬 5 comments Opened Jan 8, 2026 by runeb Closed Feb 23, 2026

Bug Description
Claude Code fails to persist refresh tokens received during exit, causing authentication failures on restart

Description

Claude Code v2.1.1 exhibits inconsistent OAuth refresh token handling with several issues:

Issue 1: Exit-time refresh tokens not persisted

When Claude Code exits and performs a token refresh during shutdown, it does not persist the new refresh token. On restart, it attempts to use a previously rotated token that has been revoked.

Observed pattern:

  1. Claude Code exits, /exit or ctrl-c x 2 (sometimes triggers a final token refresh)
  2. Server returns a new rotated refresh_token
  3. Claude Code exits without persisting this token
  4. On restart: Claude Code uses a previous refresh token instead of the latest one
  5. Result: "Invalid grant: refresh token is invalid" because the old token was revoked

Issue 2: Inconsistent error reporting

When token refresh fails, Claude Code behavior is inconsistent:

  • Sometimes it correctly reports an authentication error (1 MCP server failed)
  • Sometimes it fails silently and shows the MCP as connected and authenticated, even though the server returned an error
  • In the silent failure case, users only discover the problem when attempting to use MCP tools: "Error: Unauthorized - Session not found"

Reproduction

Testing with accelerated token expiry consistently shows Claude Code reverting to earlier refresh tokens on restart instead of using the latest token it received.

Impact

Users experience authentication failures on restart requiring re-authentication, even though valid refresh tokens were provided by the OAuth server.

Environment Info

  • Platform: darwin
  • Terminal: ghostty
  • Version: 2.1.1
  • Feedback ID: 612db877-e9b4-40ba-823e-317d1fa05050

Errors

[]

View original on GitHub ↗

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