Skip to content

Race condition in auth() causes refresh token invalidation when rotating tokens are used #1760

@DhyeyaDesai

Description

@DhyeyaDesai

Describe the bug
When two requests for the same OAuth MCP server arrive in parallel, both calls independently detect a 401, call auth(), and race to refresh using the same refresh token. With OAuth servers that use rotating refresh tokens (e.g. Atlassian, Asana), this triggers RFC 6819 5.2.2.3 replay detection — the authorization server detects that a consumed refresh token was reused and revokes the entire token family, permanently breaking the connection until the user manually re-authorizes.

To Reproduce

  1. Set up an MCP server connection using an OAuth provider with rotating refresh tokens (e.g. Atlassian)
  2. Let the access token expire, or manually add a bad token
  3. Send two parallel requests to the MCP server before either completes the refresh, this will have to be quick so use a simple script to make 2 immediate calls
curl ... &
curl ... &
wait
  • Both requests call auth() simultaneously, each POSTing to the token endpoint with the same refresh token
  • The OAuth server receives two requests with the same refresh token — the second is a replay

Expected behavior
Only one token refresh should occur. The second concurrent request should wait for the in-flight refresh to complete and reuse the resulting tokens, not trigger its own parallel refresh.

Logs

InvalidGrantError: Invalid refresh token
    at parseErrorResponse (client/auth.ts:292:16)
    at refreshAuthorization (client/auth.ts:1022:15)
    at authInternal (client/auth.ts:419:31)
    at auth (client/auth.ts:325:20)
    at StreamableHTTPClientTransport.send (client/streamableHttp.ts:442:36)

Additional context
Root cause is in auth() in client/auth.ts — there is no concurrency guard preventing two simultaneous refresh flows for the same provider.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions