Conversation
…ience IdentityAssertionGrantProvider passed authorizationServerUrl.ToString() as the RFC 8693 audience. Uri.ToString() appends a trailing slash to an empty path, so the common case (https://auth.example.com, whose metadata advertises the issuer without a slash) sent an audience that did not match the issuer. Use the issuer from the authorization server metadata already fetched in step 1, falling back to the configured URL when the metadata omits it. Fixes modelcontextprotocol#1617 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This branch has not been deployed
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.
Fixes #1617
Problem
IdentityAssertionGrantProvidersendsauthorizationServerUrl.ToString()as theaudienceof the RFC 8693 token exchange at the IdP. That value isn't guaranteed to match the MCP authorization server's issuer identifier, and in the most common setup it doesn't:new Uri("https://auth.example.com").ToString()returns"https://auth.example.com/", while the metadata advertises"issuer": "https://auth.example.com". An IdP that compares the audience against the issuer exactly will reject the exchange.Fix
Use the
issuerfrom the authorization server metadata that step 1 of the flow already fetches (mcpAuthMetadata).Issuer.OriginalStringis used so the value is sent exactly as published, sinceUri.ToString()would reintroduce the same trailing-slash normalization. This matches howClientOAuthProvidercompares issuers, and the direction taken by the Python SDK (override_audience_with_issuer, modelcontextprotocol/python-sdk#1721).If the metadata doesn't include an
issuer, it falls back to the previous behavior, so nothing that works today changes.Scope is limited to the audience, as described in the issue.
resourceis left as is.Tests
Added
IdentityAssertionGrantProvider_UsesDiscoveredIssuerAsJagAudience(theory), which reads theaudienceform field sent to the IdP:https://auth.example.comhttps://auth.example.comhttps://auth.example.comhttps://auth.example.com/https://auth.example.com/tenanthttps://auth.example.com/tenanthttps://auth.example.comhttps://auth.example.com/(fallback)The first two cases fail on
main(actual:https://auth.example.com/) and pass with this change.IdentityAssertionGrantTestsand the AspNetCoreOAuthintegration tests pass locally on net10.0, net9.0, net8.0 and net472. The fullModelContextProtocol.Testssuite also passes on net10.0 (2399 tests, 6 skipped because they need an OpenAI key).🤖 Generated with Claude Code