MCP OAuth: client performs full re-authorization at session start while valid refresh tokens exist
Summary
Claude Code intermittently discards its stored MCP OAuth credentials and runs a full authorization-code flow at session start, without ever attempting a token refresh. As the operator of the MCP server on the other side of this, I can confirm the refresh tokens it abandoned were still valid and would have been honored.
Evidence (server-side)
I run the OAuth server for the MCP in question, so I have the authoritative view of what the client did and did not send. On a re-auth event today:
- Full code flow observed:
code_issued→code_consumed→token_issued - At that moment the grant held 4 live, unexpired refresh tokens (newest issued ~40 minutes earlier)
- No refresh attempt was made before the re-auth: no
invalid_grant, no rejection, no request at all - The grant was never revoked (
revoked_atis null, created 12 days earlier) - Zero refresh rejections for this user in the preceding 36 hours; 6,170 successful refreshes across all users in a 21-day window
This is not the server rejecting a refresh. The client is deciding locally that it has no credentials.
Frequency
Full interactive re-auths for a single user on 7/11, 7/14, 7/15, 7/18, 7/21, 7/22, 7/28, 7/30 — each at session startup. On 7/28 the re-auth timestamp matched the exact minute a VS Code session started.
The disconnect surfaces mid-session as the MCP's tools vanishing from the tool list, which interrupts any in-flight tool call.
Expected behavior
At session start, attempt a refresh with the stored refresh token before falling back to interactive authorization.
Actual behavior
Interactive authorization is triggered directly, while valid refresh tokens are on hand.
Environment
- Claude Code in VS Code
- macOS 15 (Darwin 25.5.0)
- Remote MCP server, OAuth 2.1 + Dynamic Client Registration, rotating single-use refresh tokens
- Access token TTL 12h, refresh TTL 60d
Possibly related
#25245 (keychain read-back failures), #24317 (concurrent session credential clobbering), #28901 (4096-byte security -i truncation), #65036 (no proactive refresh at startup).
#65036 looks closest, but the credential loss pattern suggests a storage failure rather than only a missing refresh call — the client behaves as though the credentials are absent, not as though it forgot to use them.
Impact
Low severity, but it recurs several times a week and interrupts in-flight tool calls. Happy to supply further server-side audit detail if useful for triage.
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗