Skip to content

Implement SEP-985: OAuth Protected Resource Metadata discovery fallback#1548

Merged
maxisbey merged 4 commits into
modelcontextprotocol:mainfrom
cbcoutinho:feat/sep-985
Nov 5, 2025
Merged

Implement SEP-985: OAuth Protected Resource Metadata discovery fallback#1548
maxisbey merged 4 commits into
modelcontextprotocol:mainfrom
cbcoutinho:feat/sep-985

Conversation

@cbcoutinho
Copy link
Copy Markdown
Contributor

Summary

Implements SEP-985 to align OAuth 2.0 Protected Resource Metadata discovery with RFC 9728. This update makes WWW-Authenticate headers optional and adds support for well-known URI fallback, enabling more flexible server deployment models.

Changes

  • Discovery State Management: Added discovery_urls and discovery_index fields to OAuthContext to track fallback URL attempts
  • Multi-Step Discovery: Implemented _build_protected_resource_discovery_urls() to generate ordered list of discovery URLs:
    1. WWW-Authenticate header resource_metadata parameter (if present)
    2. Path-based well-known URI: /.well-known/oauth-protected-resource/{path}
    3. Root-based well-known URI: /.well-known/oauth-protected-resource
  • Fallback Logic: Updated async_auth_flow() to loop through discovery URLs until one succeeds or all are exhausted
  • Response Handling: Modified _handle_protected_resource_response() to return boolean indicating success, enabling automatic fallback on 404 or validation errors

Test Coverage

Added comprehensive TestSEP985Discovery test class with three scenarios:

  • Path-based well-known URI fallback when WWW-Authenticate header is absent
  • Root-based well-known URI fallback when path-based returns 404
  • WWW-Authenticate header priority over well-known URIs

All existing tests pass (92 passed, 1 xfailed as expected).

Motivation

SEP-985 addresses deployment challenges in large-scale, multi-tenant environments where injecting WWW-Authenticate headers from backend services is complex due to separation of concerns. By making headers optional and requiring well-known URI support, servers can choose the discovery mechanism that best fits their architecture.

Test Plan

  • Run client auth tests: pytest tests/client/test_auth.py
  • Run server auth tests: pytest tests/server/auth/
  • Verify all SEP-985 specific tests pass
  • Confirm no regressions in existing tests
  • Test backward compatibility with servers using only WWW-Authenticate headers

References

cbcoutinho and others added 3 commits October 30, 2025 14:43
Add support for multiple discovery mechanisms when WWW-Authenticate header
is absent, aligning with RFC 9728 requirements. Clients now try discovery
URLs in order: WWW-Authenticate header resource_metadata parameter,
path-based well-known URI, then root-based well-known URI.

Changes:
- Add discovery state tracking to OAuthContext (discovery_urls, discovery_index)
- Implement _build_protected_resource_discovery_urls() to generate ordered URL list
- Update _discover_protected_resource() to support multi-step discovery
- Modify _handle_protected_resource_response() to return success/failure boolean
- Update async_auth_flow() to loop through discovery URLs with fallback logic
- Add comprehensive test coverage for all three discovery mechanisms

This enables servers to choose between WWW-Authenticate headers and
well-known URIs based on their deployment architecture, reducing
integration complexity for large-scale, multi-tenant environments.

Github-Issue: modelcontextprotocol#1341

Co-Authored-By: Claude <noreply@anthropic.com>
@pcarleton pcarleton requested a review from maxisbey October 30, 2025 15:56
@pcarleton
Copy link
Copy Markdown
Member

thanks @cbcoutinho ! I added a few tweaks to be more similar to OAuth Authorization Server metadata discovery (step 3) and eliminate additions to context.