[Bug] Exit-time refresh tokens not persisted, causing invalid grant errors on restart
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:
- Claude Code exits, /exit or ctrl-c x 2 (sometimes triggers a final token refresh)
- Server returns a new rotated
refresh_token - Claude Code exits without persisting this token
- On restart: Claude Code uses a previous refresh token instead of the latest one
- 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
[]This issue has 5 comments on GitHub. Read the full discussion on GitHub ↗