Skip to content

Validate the issuer of machine-to-machine providers as an issuer URL - #682

Open
koic wants to merge 1 commit into
modelcontextprotocol:mainfrom
koic:validate_the_issuer_of_machine_to_machine_providers_as_an_issuer_url
Open

koic wants to merge 1 commit into
modelcontextprotocol:mainfrom
koic:validate_the_issuer_of_machine_to_machine_providers_as_an_issuer_url

Conversation

@koic

@koic koic commented Nov 13, 2026

Copy link
Copy Markdown
Member

Motivation and Context

issuer: on ClientCredentialsProvider and CrossAppAccessProvider accepted any non-empty String. A value that is not an issuer URL can never match the metadata of an authorization server, so such credentials were refused at the first request with a message about a different authorization server, far from the configuration that caused it. The flow accepts an authorization server over HTTPS, or over HTTP on a loopback address, and the option is now held to the same rule at construction, where a mistake is reported with the value that was given. Since the issuer of the metadata is compared as a String, a URI object or a Symbol could never equal it either, nor could an issuer with a query or fragment, which RFC 8414 rules out; both are refused the same way. The Python SDK requires an http(s) scheme on its issuer; the rule here is the stricter one the flow already applies to every authorization server URL.

How Has This Been Tested?

test/mcp/client/oauth/client_credentials_provider_test.rb and test/mcp/client/oauth/cross_app_access_provider_test.rb: a bare host, a non-HTTP scheme, a URL without a host, a plain HTTP URL off the loopback, a query, a fragment, a URI object and a Symbol are refused with the new message, and HTTPS and loopback HTTP issuers (IPv6 and an uppercase scheme included) are kept; before the change the String values among them were accepted.

Breaking Changes

None for an issuer: that names an authorization server. A value that could never have matched a compliant one (RFC 8414 forbids a query or fragment in an issuer) is refused at construction instead of at the first request.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

## Motivation and Context

`issuer:` on `ClientCredentialsProvider` and `CrossAppAccessProvider` accepted any non-empty String.
A value that is not an issuer URL can never match the metadata of an authorization server,
so such credentials were refused at the first request with a message about a different authorization server,
far from the configuration that caused it. The flow accepts an authorization server over HTTPS,
or over HTTP on a loopback address, and the option is now held to the same rule at construction,
where a mistake is reported with the value that was given. Since the issuer of the metadata is compared as a String,
a URI object or a Symbol could never equal it either, nor could an issuer with a query or fragment,
which RFC 8414 rules out; both are refused the same way. The Python SDK requires an http(s) scheme on its `issuer`;
the rule here is the stricter one the flow already applies to every authorization server URL.

## How Has This Been Tested?

test/mcp/client/oauth/client_credentials_provider_test.rb and test/mcp/client/oauth/cross_app_access_provider_test.rb:
a bare host, a non-HTTP scheme, a URL without a host, a plain HTTP URL off the loopback, a query, a fragment,
a URI object and a Symbol are refused with the new message, and HTTPS and loopback HTTP issuers
(IPv6 and an uppercase scheme included) are kept; before the change the String values among them were accepted.

## Breaking Changes

None for an `issuer:` that names an authorization server. A value that could never have matched a compliant one
(RFC 8414 forbids a query or fragment in an issuer) is refused at construction instead of at the first request.
@koic
koic force-pushed the validate_the_issuer_of_machine_to_machine_providers_as_an_issuer_url branch from b44a73c to 247d83b Compare November 13, 2026 04:37

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants