Add subject and claims to AccessToken#2686
Merged
Merged
Conversation
Adds optional `subject` and `claims` fields to `AccessToken` so token verifiers can surface the resource owner (`sub`) and any additional claims to request handlers. `subject` is also added to `AuthorizationCode` and `RefreshToken` so the value can be carried through code-for-token exchange and token refresh. `Context.subject` exposes the value to tool and resource handlers. The simple-auth example is updated to thread the subject from login through introspection. Closes #1038. Reported-by: Thomas Steinacher <@thomasst> Reported-by: Yukuan Jia <@yukuanj> Reported-by: Shivam Aggarwal <@shivama205>
- Reword AccessToken.subject's client_credentials note to match RFC 9068 §2.2 (sub may identify the client itself rather than being unset). - Add Context.claims so handlers can read iss/act/etc without importing get_access_token and handling the raw token model. - Document that Context.client_id reads MCP request _meta, not the OAuth client_id, so it isn't mistaken for the pair to Context.subject.
Kludex
reviewed
May 26, 2026
Kludex
reviewed
May 26, 2026
Kludex
reviewed
May 26, 2026
Kludex
reviewed
May 26, 2026
Kludex
reviewed
May 26, 2026
Kludex
reviewed
May 26, 2026
- Drop Context.subject/Context.claims; handlers use get_access_token() directly for now. A designed Context auth surface can follow separately. - Collapse AccessToken.subject/claims docstrings to one-line comments to match surrounding fields. - Move the client_id TODO to a # comment and tighten its docstring note. - Replace the trivial model and contextvar unit tests with subject propagation through MockOAuthProvider in test_auth_integration.py, so test_authorization_get now asserts subject survives the full /authorize -> /token -> refresh flow over HTTP.
Kludex
previously approved these changes
May 26, 2026
Contributor
Author
|
waiting on @pcarleton review before merging :) |
pcarleton
previously approved these changes
May 26, 2026
Member
There was a problem hiding this comment.
A few non-blocking suggestions, mostly on the example since it's what people copy:
examples/.../auth_server.py(introspection response): also returniss, e.g."iss": str(server_settings.server_url),—subis only unique per issuer, and the example currently never exposes the issuer anywhere in the data path, so a resource server can't key identity on(iss, sub)even if it wants to.examples/.../simple_auth_provider.py: consider a stable id rather than the login username assubject(usernames get renamed/reused) — e.g. theuser_idthis method already generates and discards a few lines later.src/mcp/server/auth/provider.py: nit — worth squeezing "only unique within the issuing AS; may be absent" into thesubjectcomment, and dropping "verified" from theclaimscomment (the SDK can't promise that; it's whatever the verifier returned). Might also consider calling this "extra" since it's the full introspection response, not just claims.
- Example introspection response now includes iss so resource servers can key identity on (iss, sub). - subject comment notes uniqueness is per-issuer; drop "verified" from the claims comment since the SDK only stores what the verifier returns. - Keep subject=username in the example: the nearby user_id is regenerated per login and would not be a stable subject.
felixweinberger
approved these changes
May 26, 2026
This was referenced May 26, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds optional
subjectandclaimsfields toAccessTokenso token verifiers can surface the resource owner (sub) and any additional claims to request handlers, and addssubjecttoAuthorizationCodeandRefreshTokenso the value can be carried through code-for-token exchange and refresh.Context.subjectexposes the value to tool and resource handlers.The simple-auth example is updated to thread the subject from login through the introspection response and back into the verifier.
Closes #1038. Supersedes #2209 and #1517 — this combines #2209's
subject+claimsfields andContext.subjectaccessor with #1517's threading through the authorization-code flow and example verifier, and addsRefreshToken.subjectwhich both were missing. Thanks to @thomasst, @yukuanj, and @shivama205 for the prior work.Motivation
Request handlers often need to make decisions based on which end-user a token was issued for, not just which OAuth client.
AccessTokenpreviously carried onlyclient_id. The other SDKs already expose this — Go'sTokenInfo.UserID, C#'sClaimsPrincipal— and theclaimsdict gives an extension point foriss,act, and deployment-specific values without further model changes.Test plan
Context.subjecttests covering authenticated / unauthenticated / no-subjectBreaking changes
None. All new fields are optional with
Nonedefaults.AI Disclaimer