Skip to content

Conversation

@sunishsheth2009
Copy link
Contributor

@sunishsheth2009 sunishsheth2009 commented Jul 15, 2025

Updating the Authorization spec to fallback to WWW-Authenticate when Protected Resource Metadata is not found

Motivation and Context

According to the current spec, it is a MUST to implement the OAuth 2.0 Protected Resource Metadata which aligns with the RFC.

Also according to the current spec,
it is a MUST to use the HTTP header WWW-Authenticate when returning a _401 Unauthorized_ to indicate the location of the resource server metadata URL.
This might not aligned with the RFC which states that: A protected resource MAY use the WWW-Authenticate HTTP response header field, as discussed in RFC9110, to return a URL to its protected resource metadata to the client.

Rationale

Many large-scale, dynamic, multi-tenant environments rely on a centralized authentication service separate from the backend resource servers. In such deployments, injecting WWW-Authenticate headers from backend services is non-trivial due to separation of concerns and infrastructure complexity.

In these scenarios, having the option to discover metadata via a well-known URL provides a practical path forward for easier MCP adoption. Requiring only the header would impose significant communication overhead between components, especially when hundreds or thousands of MCP instances are created and destroyed dynamically. Also if there are specific managed MCP servers, adopting headers across centralized system would add significant overhead.

While this increases complexity for clients—who must now implement logic to probe metadata endpoints—it reduces friction for server deployments and may encourage broader adoption. There are tradeoffs:

Pros for Server Developers: Avoid complex header injection; simplifies integration in distributed environments.

Cons for Client Developers: Clients must fall back to metadata discovery logic when the header is absent, increasing client complexity.

Proposed State

Update the MCP spec to:

Clients MUST interpret the WWW-Authenticate header, and fallback to probing for metadata if not present.
Servers SHOULD return the WWW-Authenticate header

The reason for deviating a bit on the RFC:
Go with SHOULD over MAY for WWW-Authenticate is that it makes supporting other features, such as incremental authorization easier (e.g. you make a request for a tool, but need additional scopes, and receive a WWW-Authenticate challenge indicating the scopes).

Based on the above, following the updated flow:

  • Attempt the MCP request without a token.
  • If a 401 Unauthorized response is received: Check for a WWW-Authenticate header. If present and includes the resource_metadata parameter, use it to locate the resource metadata.
  • If the header is absent or does not include resource_metadata, fallback to requesting /.well-known/oauth-protected-resource.

This change allows more flexible deployment models without removing existing capabilities.

How Has This Been Tested?

Have you tested this in a real application? Which scenarios were tested?

Updating the spec according to the RFC

Breaking Changes

Will users need to update their code or configurations?

Yes some clients would need to update if they solely rely on WWW-Authenticate header and rather use this as a fallback instead.

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

Additional context

@localden localden requested review from localden and pcarleton and removed request for pcarleton July 15, 2025 19:21
@localden localden requested review from aaronpk and pcarleton July 15, 2025 19:22
@localden
Copy link
Contributor

I need to think a bit more deeply about this, but I almost feel like a MUST for WWW-Authenticate is a better developer experience. You have one entrypoint for discovering the PRM document that is standard for all MCP servers and don't need to compose the URI manually. I know the PRM spec is a MAY, but in the context of MCP this feels like a reasonable pivot.

@aaronpk @D-McAdams - thoughts?

@000-000-000-000-000
Copy link
Contributor

I need to think a bit more deeply about this, but I almost feel like a MUST for WWW-Authenticate is a better developer experience. You have one entrypoint for discovering the PRM document that is standard for all MCP servers and don't need to compose the URI manually. I know the PRM spec is a MAY, but in the context of MCP this feels like a reasonable pivot.

@aaronpk @D-McAdams - thoughts?

agree with @localden i think it might be better to enforce this for now. Philosophically, imo it is not necessary we be as open as the RFC i.e. we are a specific implementation of OAuth and hence can be more opinionated.

@D-McAdams
Copy link

As it stands, the MCP spec requires OAuth and OAuth mechanisms. If I'm understanding correctly, the proposal suggests making these OAuth components optional to accommodate situations where OAuth isn't being used. However, without a compelling use case that aligns with the spec's core security and interoperability goals, I don't believe we should modify the specification to make these requirements optional.

@dsp-ant
Copy link
Member

dsp-ant commented Jul 15, 2025

This should be a Specification Enhancement Proposal tracked as an Github issue with this PR associated.

@pcarleton pcarleton linked an issue Jul 17, 2025 that may be closed by this pull request
@sunishsheth2009 sunishsheth2009 force-pushed the sunish-update-auth-spec branch from b4c2c14 to 5ca0394 Compare July 28, 2025 16:59
@sunishsheth2009 sunishsheth2009 requested review from a team July 28, 2025 16:59
@sunishsheth2009 sunishsheth2009 force-pushed the sunish-update-auth-spec branch from 5ca0394 to 1a47dab Compare July 28, 2025 17:05
@000-000-000-000-000
Copy link
Contributor

Can we make this a MUST implement one of the following w/ WWW-Authenticate being one of the options? Would rather have a very clear / fixed set of options.

@pcarleton
Copy link
Member

I've made the changes to make the MUST clearer for the server, and updated the mermaid diagram similarly.

@sunishsheth2009 can you check this works for you?

@000-000-000-000-000 can you check the wording on this?

@sunishsheth2009
Copy link
Contributor Author

I've made the changes to make the MUST clearer for the server, and updated the mermaid diagram similarly.

@sunishsheth2009 can you check this works for you?

@000-000-000-000-000 can you check the wording on this?

Yes this makes sense to me. :) Thank you for the updating it.

pcarleton
pcarleton previously approved these changes Aug 22, 2025
Copy link
Member

@pcarleton pcarleton left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Marking approved, this was voted on via async discord poll by the core-maintainers.

Copy link

@D-McAdams D-McAdams left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be beneficial to specify an order of precedence for MCP Clients. As written, it says "MCP clients MUST support both discovery mechanisms..." and that would leave ambiguity on whether implementations must query all possible locations and reconcile conflicting results. I believe the desired order of preference is (1) Use the WWW-Authenticate information if it exists in the HTTP 401, (2) Else, fallback to the Well-Known URI the sub-path, (3) Finally, fallback to the Well-Known URI at the root.


2. **Well-Known URI**: Serve metadata at a well-known URI as specified in [RFC9728](https://datatracker.ietf.org/doc/html/rfc9728). This can be either:
- At a sub-path: `https://example.com/.well-known/oauth-protected-resource/mcp`
- At the root: `https://example.com/.well-known/oauth-protected-resource`

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this fallback logic to the root part of RFC9728? Or, is this included because implementations haven't conformed to RFC9728 and we're practically adapting to that? I'd question this more if we're deviating from RFC9728 in order to meet non-compliant implementations.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 to what @D-McAdams mentioned here - this feels like an "either or" choice that really should not be here, no? The metadata location should correspond to the server location.

Copy link
Member

@pcarleton pcarleton Aug 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a good question. My understanding is that it is compliant with RFC9728, and makes it more explicit which "resource identifier" values MCP will consider. If we didn't have implementations with it at the root, I think we would leave it out.

Protected resources supporting metadata MUST make a JSON document containing metadata as specified in Section 2 available at a URL formed by inserting a well-known URI string into the protected resource's resource identifier between the host component and the path and/or query components, if any. By default, the well-known URI string used is /.well-known/oauth-protected-resource.

From what I understand, and from discussing with @aaronpk , the definition "resource identifier" in RFC 9728 is what this hinges on, which can vary and is not necessarily the MCP server URL (e.g. it can be at the root or at the /mcp path).

In a multi-tenant environment, I need to specify a resource identifier with a path in order to separate access between tenants. In a single tenant environment, I can choose which resource identifier makes the most sense for me, it might either be at the root of my domain, or it might be at the /mcp path.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dumped some previous discussions on this in to this discord thread, but tl;dr is that I believe that "specific path" then "root" as written is compliant with RFC 9728 and RFC 8707

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@D-McAdams / @dend
I think realistically SDK's will need to support the fallback since the spec was ambiguous before this and many assumed the root was the proper place. I'd prefer then to have the spec be descriptive.

based on everything above, what's your take?

Should we be strict or lax here? i.e. require using the most specific, or allow a fallback to root?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I'm OK with the fallback. For this to go wrong in production and result in an exploit, the server needs to make two mistakes: Forget to host a PRM document of it's own, and not validate the 'aud' in the token it subsequently receives.


2. **Well-Known URI**: Serve metadata at a well-known URI as specified in [RFC9728](https://datatracker.ietf.org/doc/html/rfc9728). This can be either:
- At a sub-path: `https://example.com/.well-known/oauth-protected-resource/mcp`
- At the root: `https://example.com/.well-known/oauth-protected-resource`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 to what @D-McAdams mentioned here - this feels like an "either or" choice that really should not be here, no? The metadata location should correspond to the server location.

Co-authored-by: Den Delimarsky <hi@den.dev>
@ochafik ochafik changed the title Updating the Authorization spec to fallback to WWW-Authenticate when Protected Resource Metadata is not found SEP-985: Updating the Authorization spec to fallback to WWW-Authenticate when Protected Resource Metadata is not found Sep 4, 2025
Co-authored-by: Geoff Goodman <ggoodman@gmail.com>
D-McAdams
D-McAdams previously approved these changes Sep 17, 2025
@pcarleton
Copy link
Member

Could I get a restamp @localden / @D-McAdams ?

@pcarleton pcarleton merged commit 95ed261 into modelcontextprotocol:main Sep 19, 2025
2 checks passed
cbcoutinho added a commit to cbcoutinho/typescript-sdk that referenced this pull request Oct 25, 2025
Aligns OAuth 2.0 Protected Resource Metadata handling with RFC 9728 and
SEP-985 by making the WWW-Authenticate header optional and implementing
graceful fallback behavior.

Changes:
- Updated discoverOAuthProtectedResourceMetadata() to return undefined
  instead of throwing on 404, making protected resource metadata optional
- Enhanced JSDoc comments to document SEP-985 fallback behavior
- Updated authInternal() to handle optional metadata with proper null checks
- Added comprehensive test suite for SEP-985 scenarios:
  - WWW-Authenticate header with resource_metadata present
  - WWW-Authenticate header without resource_metadata (fallback to well-known)
  - Missing WWW-Authenticate header (fallback to well-known)
  - 404 on well-known endpoint (graceful degradation)
  - CORS errors on metadata discovery (graceful fallback)
- Updated existing tests to expect undefined instead of errors on 404

Per SEP-985, clients now:
1. Check WWW-Authenticate header for resource_metadata parameter
2. Fallback to /.well-known/oauth-protected-resource if not present
3. Continue gracefully using the MCP server as auth server if metadata unavailable

All 856 tests pass.

Related: modelcontextprotocol#920
Implements: SEP-985 (modelcontextprotocol/modelcontextprotocol#971)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

SEP-985: Align OAuth 2.0 Protected Resource Metadata with RFC 9728

9 participants