-
Notifications
You must be signed in to change notification settings - Fork 1.9k
fix: propagate upstream_claims in load_access_token #3750
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
9479e45
a0cd28b
c7c0c1a
24d8f6b
385154b
9d188bd
3ffde06
2cd77ef
53b3736
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1571,6 +1571,7 @@ async def load_access_token(self, token: str) -> AccessToken | None: # type: ig | |
| # 1. Verify FastMCP JWT signature and claims | ||
| payload = self.jwt_issuer.verify_token(token) | ||
| jti = payload["jti"] | ||
| upstream_claims = payload.get("upstream_claims") | ||
|
|
||
| # 2. Look up upstream token via JTI mapping | ||
| jti_mapping = await self._jti_mapping_store.get(key=jti) | ||
|
|
@@ -1693,6 +1694,17 @@ async def load_access_token(self, token: str) -> AccessToken | None: # type: ig | |
| } | ||
| ) | ||
|
|
||
| # Propagate upstream claims from the verified FastMCP JWT into the | ||
| # final AccessToken object. This allows subclasses to access custom | ||
| # identity data extracted during the initial authorization flow. | ||
| # We perform a model copy to avoid mutating a potentially cached | ||
| # reference shared across concurrent requests. | ||
| if validated and upstream_claims: | ||
| validated = validated.model_copy(deep=True) | ||
| if validated.claims is None: | ||
| validated.claims = {} | ||
| validated.claims["upstream_claims"] = upstream_claims | ||
|
Comment on lines
+1697
to
+1706
|
||
|
|
||
| logger.debug( | ||
| "Token swap successful for JTI=%s (upstream validated)", jti[:8] | ||
| ) | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
load_access_tokenmutatesvalidated.claimsin place, but some verifiers (notablyIntrospectionTokenVerifier) return cachedAccessTokeninstances by reference (src/fastmcp/server/auth/providers/introspection.py:197-200,292). In that setup, this write can leak/overwrite claim state across requests sharing the same upstream token object; e.g., a request withupstream_claimscan persist data that is then returned for a later token whereupstream_claimsis absent (the branch is skipped, so stale data remains). Copying the token/claims before mutation avoids cross-request contamination.Useful? React with 👍 / 👎.