Skip to content

fix(client): deduplicate concurrent OAuth refreshes - #2757

Open
CharlesMcMillan wants to merge 3 commits into
modelcontextprotocol:mainfrom
CharlesMcMillan:fix/deduplicate-concurrent-oauth-refresh
Open

fix(client): deduplicate concurrent OAuth refreshes#2757
CharlesMcMillan wants to merge 3 commits into
modelcontextprotocol:mainfrom
CharlesMcMillan:fix/deduplicate-concurrent-oauth-refresh

Conversation

@CharlesMcMillan

@CharlesMcMillan CharlesMcMillan commented Sep 4, 2026

Copy link
Copy Markdown

Summary

Prevent overlapping OAuth refresh calls from redeeming the same rotating refresh token. Equivalent calls sharing a provider share one pending result; calls with different auth options are serialized and execute their own discovery and validation. Authorization-code exchanges and forced reauthorization remain distinct operations.

Hosts sharing credentials across processes can implement the optional withAuthTransaction provider hook. It wraps the complete auth operation, including error recovery and persistence, so hosts can release ownership in one finally instead of inferring completion from individual provider callbacks. No lock spans browser consent.

The client decoder also treats error_description: null as omitted, preserving an authorization server's invalid_grant classification. The public OAuth schema stays strict.

Fixes #1760. Replaces #1813. Adapter integration: nicobailon/pi-mcp-adapter#528.

Verification

  • 906 client tests pass, including 23 transaction/parser tests and joining an already-running refresh.
  • Client check/build and workspace typecheck/lint pass.
  • The optional hook is exercised by a six-process adapter integration test using single-use rotating fake tokens; production credentials are not used.
  • Local E2E protocol timeout errors also reproduce at baseline 5119ee7f; published CI is checked separately for each PR head.

@CharlesMcMillan
CharlesMcMillan requested a review from a team as a code owner September 4, 2026 19:03
@changeset-bot

changeset-bot Bot commented Sep 4, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 3b205e7

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 6 packages
Name Type
@modelcontextprotocol/client Patch
@modelcontextprotocol/codemod Patch
@modelcontextprotocol/core Patch
@modelcontextprotocol/server-legacy Patch
@modelcontextprotocol/server Patch
@modelcontextprotocol/core-internal Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@CharlesMcMillan

Copy link
Copy Markdown
Author

@claude review

@pkg-pr-new

pkg-pr-new Bot commented Sep 4, 2026

Copy link
Copy Markdown

Open in StackBlitz

@modelcontextprotocol/client

npm i https://pkg.pr.new/@modelcontextprotocol/client@2757

@modelcontextprotocol/codemod

npm i https://pkg.pr.new/@modelcontextprotocol/codemod@2757

@modelcontextprotocol/core

npm i https://pkg.pr.new/@modelcontextprotocol/core@2757

@modelcontextprotocol/server

npm i https://pkg.pr.new/@modelcontextprotocol/server@2757

@modelcontextprotocol/server-legacy

npm i https://pkg.pr.new/@modelcontextprotocol/server-legacy@2757

@modelcontextprotocol/express

npm i https://pkg.pr.new/@modelcontextprotocol/express@2757

@modelcontextprotocol/fastify

npm i https://pkg.pr.new/@modelcontextprotocol/fastify@2757

@modelcontextprotocol/hono

npm i https://pkg.pr.new/@modelcontextprotocol/hono@2757

@modelcontextprotocol/node

npm i https://pkg.pr.new/@modelcontextprotocol/node@2757

commit: 3b205e7

Wrap complete auth recovery in an optional provider transaction. Serialize incompatible ordinary calls without dropping their options, while code exchange and forced reauthorization continue to bypass the queue. Normalize null error descriptions only at the client parser boundary.
@CharlesMcMillan
CharlesMcMillan marked this pull request as draft September 6, 2026 20:20
@CharlesMcMillan

Copy link
Copy Markdown
Author

@claude review

@CharlesMcMillan

Copy link
Copy Markdown
Author

Current head 3b205e7 has one failing check: client-conformance reports sse-retry as 2 passes plus a timing warning. The isolated scenario passes locally (503 ms reconnect vs 500 ms target), while the auth scenarios pass in CI. I cannot rerun the failed job with contributor permissions (GitHub requires repository admin rights). Could a maintainer rerun job 101554954460 / run 34058603161? No test suppression or unrelated SSE changes are included.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

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

1 participant