[Bug] MCP OAuth refresh tokens stored but never used - causing widespread auth failures

Resolved 💬 3 comments Opened Jan 27, 2026 by aneym Closed Jan 31, 2026

Summary

Claude Code stores MCP OAuth refresh tokens but never uses them to refresh expired access tokens. This causes authentication failures requiring manual re-authentication, sometimes multiple times per day.

Evidence

Refresh tokens ARE stored

// From macOS Keychain - Claude Code-credentials
"supabase|...": {
  "accessToken": "sbp_oauth_...",
  "refreshToken": "UVemFCAEqbCNEpPqkG",  // ← Stored but never used
  "expiresAt": 1769635674007
}

MCP servers DO support refresh

Both Linear and Sentry OAuth metadata explicitly support refresh tokens:

// https://mcp.linear.app/.well-known/oauth-authorization-server
// https://mcp.sentry.dev/.well-known/oauth-authorization-server
"grant_types_supported": ["authorization_code", "refresh_token"]

Tokens expire with no refresh attempt

After ~24 hours (or less), tokens expire and users see:

  • "Invalid grant: refresh token is invalid"
  • MCP servers showing empty accessToken: "" and expiresAt: 0
  • Silent failures where MCP appears connected but returns "Unauthorized"

Impact

  • Atlassian Rovo MCP: "basically unusable after ~5 minutes" (see #5706)
  • Microsoft OAuth users: 60-90 minute token TTL = constant re-auth
  • Autonomous workflows: Fail mid-execution when tokens expire
  • Developer productivity: Multiple manual re-authentications per day

MCP Spec Compliance

The MCP Authorization spec states:

"Authorization servers SHOULD issue short-lived access tokens to reduce the impact of leaked tokens."

This implies clients MUST implement refresh token handling. Claude Code does not.

Related Issues (20+)

This is the root cause of many fragmented issues:

| Issue | Problem |
|-------|---------|
| #5706 | Original feature request (7+ months, no response) |
| #16957 | Exit-time refresh tokens not persisted |
| #19456 | Keychain permission errors on token update |
| #12447 | OAuth expiration disrupts autonomous workflows |
| #19481 | /mcp reconnect doesn't refresh expired tokens |
| #10784 | OAuth expiration causes retry storm (3.75M wasted tokens) |
| #18225 | Repeated 401 errors during active sessions |
| #10250 | OAuth succeeds but MCP reconnection fails |

Expected Behavior

  1. When access token expires, Claude Code should use stored refresh token
  2. On successful refresh, persist new access + refresh tokens
  3. On refresh failure, prompt user to re-authenticate (not fail silently)

Environment

  • Claude Code: 2.1.x (affects multiple versions)
  • Platform: macOS (also reported on Linux)
  • MCP servers affected: Linear, Sentry, Supabase, Atlassian, custom OAuth servers

---

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>

View original on GitHub ↗

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