Skip to content

[Client] Keep a client another worker registered when dropping a refused one - #725

Merged
chr-hertel merged 1 commit into
modelcontextprotocol:mainfrom
chr-hertel:forget-refused-registration-locked
Nov 10, 2026
Merged

chr-hertel merged 1 commit into
modelcontextprotocol:mainfrom
chr-hertel:forget-refused-registration-locked

Conversation

@chr-hertel

Copy link
Copy Markdown
Member

When the token endpoint answers invalid_client for a dynamically registered client, the authenticator drops the registration of the issuer. It did that without checking whether the stored registration is still the client that was refused - so if another worker registered a new client in the meantime, that one got dropped, together with its tokens.

The approach:

  • forgetRefusedClient() only forgets the issuer if the stored registration still has the client id that was refused
  • check and forget() run inside storage->synchronize() - the same lock resolveClient() holds while it registers, so no registration can land in between
  • both call sites use it: the refresh that re-registers right away, and the code exchange that fails once

The tests use a storage double that swaps in another worker's registration right after the authenticator picked up the old one. Without the fix the refresh registers a third client and the code exchange drops the other worker's one.

Spotted while reviewing #660, which needs the same for a deferred callback.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

The supplied review evidence identifies no active issues with the OAuth client cleanup race fix.

No open issues 🎉

What changed in this PR

This PR fixes an OAuth client cleanup race so an invalid_client response does not delete a replacement registration and its tokens saved by another worker.

Changes:

  • Check the stored client ID and remove the refused registration under the registration lock, covering both refresh and authorization-code exchange failures.
  • Add regression tests that simulate another worker replacing the registration.
File Description
tests/​Unit/​Client/​Auth/​OAuthAuthenticatorTest.php Adds concurrent-registration regression tests and a storage double.
src/​Client/​Auth/​OAuthAuthenticator.php Adds synchronized, client-ID-checked cleanup at both failure paths.

Review effort: Balanced

@chr-hertel
chr-hertel merged commit e2f4b97 into modelcontextprotocol:main Nov 10, 2026
30 checks passed
@chr-hertel
chr-hertel deleted the forget-refused-registration-locked branch November 10, 2026 09:58
@chr-hertel chr-hertel added Client Issues & PRs related to the Client component auth Issues and PRs related to Authentication / OAuth labels Nov 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

auth Issues and PRs related to Authentication / OAuth Client Issues & PRs related to the Client component

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants