You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[Client] Add OAuth metadata discovery and challenge parsing - #664
Part of #317 & #318 - second slice of the client authorization in chr-hertel#53, independent of #663.
Finds and validates the documents that say who guards an MCP server: protected resource metadata (RFC 9728), authorization server metadata (RFC 8414 & OpenID Connect) and the WWW-Authenticate challenge that points at them. These documents come from a server we don't trust, so:
endpoints need https or a loopback host, with the same SecureUrl check the server side uses
a document naming another issuer than it was fetched for is discarded
covers() & isWithin() answer whether a token for a resource may go to a URL
All @internal and not used yet, the authenticator comes with the next slice - hence no changelog entry or docs. Whether the challenge's resource_metadata URL can be trusted is also decided there, MetadataDiscovery just fetches what it gets.
The reason will be displayed to describe this comment to others. Learn more.
🟡 Changes recommended
Resource containment ignores query constraints and accepts dot-segment path escapes, potentially allowing resource-scoped tokens to be sent to the wrong tenant or an out-of-scope endpoint.
Finds and validates the documents that say who guards an MCP server: protected
resource metadata (RFC 9728) and authorization server metadata (RFC 8414 and
OpenID Connect), plus the WWW-Authenticate challenge that points at them.
All of it is @internal, since nothing uses it until the authenticator lands.
Endpoints have to pass SecureUrl, and a document naming another issuer than it
was fetched for is discarded.
The reason will be displayed to describe this comment to others. Learn more.
🟡 Changes recommended
Issuer discovery accepts plaintext HTTP, allowing an on-path attacker to replace authorization and token endpoints with attacker-controlled HTTPS URLs that pass later checks.
The reason will be displayed to describe this comment to others. Learn more.
🔵 Needs a closer look
Discovery can accept unrelated resource metadata, alter meaningful issuer paths, and skip valid fallbacks, while split authentication headers can cause metadata URLs to be missed.
No open issues 🎉
4 previously missed issues
In code that hasn't changed since last review
Parse WWW-Authenticate as a combined header value
src/Client/Auth/AuthorizationChallenge.php:42
A single Bearer challenge can span multiple WWW-Authenticate field lines, which HTTP treats as one comma-joined value. For example, splitting Bearer scope="read" and resource_metadata="https://mcp.example.com/meta" across two lines makes this method return before reading the metadata URL; parse getHeaderLine('WWW-Authenticate') once so equivalent split and combined headers produce the same result.
Skip metadata that does not cover the requested resource
src/Client/Auth/MetadataDiscovery.php:53
A document naming an unrelated resource is returned without checking whether it covers $resourceUrl, so its authorization servers are accepted and a valid host-root fallback is never tried. Check covers($resourceUrl) before returning and skip documents whose resource does not cover the requested endpoint.
Continue discovery after an issuer-mismatched candidate
src/Client/Auth/MetadataDiscovery.php:97
If the RFC 8414 location returns another issuer's metadata but a later OIDC location contains the correct document, this return aborts discovery before that valid fallback is requested. Discard this candidate with continue, as for other malformed documents, while retaining the exact issuer check on each subsequent candidate.
Preserve repeated leading slashes in issuer paths
src/Client/Auth/MetadataDiscovery.php:136
trim() removes meaningful leading slashes from the issuer's path: for https://auth.example.com//tenant, all three candidates use /tenant instead of //tenant and therefore probe the wrong locations. Preserve additional leading slashes when removing the initial path separator so discovery also works for these valid issuer URLs.
The reason will be displayed to describe this comment to others. Learn more.
🔵 Needs a closer look
Human assessment is needed because trailing-slash normalization can extend resource-scoped token access beyond its intended subtree, creating a critical authorization-boundary risk.
The reason will be displayed to describe this comment to others. Learn more.
🔵 Needs a closer look
Human assessment is needed because metadata validation can approve insecure token recipients, while discovery can accept mismatched resources and derive incorrect authorization endpoints.
The reason will be displayed to describe this comment to others. Learn more.
🔵 Needs a closer look
Human assessment is needed because metadata discovery can accept a document for an unrelated resource and stop fallback before reaching valid metadata.
Human assessment is needed because metadata discovery can accept a document for an unrelated resource and stop fallback before reaching valid metadata.
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
authIssues and PRs related to Authentication / OAuthClientIssues & PRs related to the Client component
2 participants
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.
Part of #317 & #318 - second slice of the client authorization in chr-hertel#53, independent of #663.
Finds and validates the documents that say who guards an MCP server: protected resource metadata (RFC 9728), authorization server metadata (RFC 8414 & OpenID Connect) and the
WWW-Authenticatechallenge that points at them. These documents come from a server we don't trust, so:SecureUrlcheck the server side usescovers()&isWithin()answer whether a token for a resource may go to a URLAll
@internaland not used yet, the authenticator comes with the next slice - hence no changelog entry or docs. Whether the challenge'sresource_metadataURL can be trusted is also decided there,MetadataDiscoveryjust fetches what it gets.