Skip to content

fix: construct path-aware OAuth protected resource metadata URL#664

Merged
DaleSeo merged 3 commits intomainfrom
AMS-382
Mar 4, 2026
Merged

fix: construct path-aware OAuth protected resource metadata URL#664
DaleSeo merged 3 commits intomainfrom
AMS-382

Conversation

@DaleSeo
Copy link
Member

@DaleSeo DaleSeo commented Feb 25, 2026

Fixes #533

The resource_metadata URL in the WWW-Authenticate header and the .well-known endpoint route were ignoring the path component of the configured resource URL. Per RFC 9728 Section 3, the well-known URI must be formed by inserting /.well-known/oauth-protected-resource between the host and path components. This fixes OAuth metadata discovery for MCP servers deployed behind reverse proxies with path-based routing, where clients like VS Code and Claude could not authenticate.

@DaleSeo DaleSeo self-assigned this Feb 25, 2026
@apollo-librarian
Copy link

apollo-librarian bot commented Feb 25, 2026

✅ Docs preview has no changes

The preview was not built because there were no changes.

Build ID: 2ccb832fca17a885f5561e11
Build Logs: View logs


✅ AI Style Review — No Changes Detected

No MDX files were changed in this pull request.

Review Log: View detailed log

This review is AI-generated. Please use common sense when accepting these suggestions, as they may not always be accurate or appropriate for your specific context.

@DaleSeo DaleSeo marked this pull request as ready for review February 26, 2026 15:41
@DaleSeo DaleSeo requested a review from a team as a code owner February 26, 2026 15:41
@github-actions
Copy link
Contributor

github-actions bot commented Feb 26, 2026

Changeset file added - thank you!

@claude
Copy link

claude bot commented Feb 26, 2026

Review Summary

This PR fixes the OAuth protected resource metadata URL construction to properly handle path-based routing per RFC 9728 Section 3. The implementation is excellent with strong adherence to Rust best practices.

Findings: None - no issues identified

Highlights:

  • RFC Compliance: Correctly inserts /.well-known/oauth-protected-resource between host and path components per RFC 9728 Section 3
  • Performance Optimization: Pre-computes the metadata URL at initialization instead of on every request - solid improvement following Chapter 3 principles
  • Good Rust Idioms: Added Copy to ScopeMode enum - appropriate for simple enums with unit variants per Chapter 1.2
  • Excellent Test Coverage: 17 comprehensive tests (10 parametrized URL construction tests using rstest, 4 scheme validation tests, 3 integration tests) covering all edge cases including trailing slashes, query strings, fragments, ports, and deep paths - follows Chapter 5 best practices
  • Proper Error Handling: Good use of thiserror with descriptive error messages per Chapter 4.3
  • Input Validation: Validates resource URL scheme with graceful error handling
  • Clear Documentation: Well-documented function explaining RFC 9728 requirements

Test Coverage Assessment: Comprehensive. The test suite thoroughly validates the URL construction logic across all relevant scenarios with proper naming conventions and one-behavior-per-test structure.

Recommendation: ✅ Approve - This is a well-implemented bug fix with no issues found. The code follows all Rust best practices and is ready to merge.


Reviewed by Claude Code Sonnet 4.5

(
StatusCode::UNAUTHORIZED,
TypedHeader(WwwAuthenticate::Bearer {
resource_metadata: resource_metadata_url(),
Copy link
Contributor

Choose a reason for hiding this comment

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

Do you think we should add an integration test that triggers 401, parses WWW-Authenticate, and then asserts that resource_metadata is the exact RFC-style URL for a path-scoped resource?

Copy link
Member Author

Choose a reason for hiding this comment

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

Great idea! Added unauthorized_response_contains_path_scoped_resource_metadata_url.

.route(
"/.well-known/oauth-protected-resource",
get(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.

Would it be best to add a test that GETs the exact resource_metadata path that is in the header and expects 200?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yep, good call! Added get_resource_metadata_path_returns_ok which GETs the path-scoped metadata URL and asserts 200 OK.

let mut url = auth_config.resource.clone();
url.set_path("/.well-known/oauth-protected-resource");
url
};
Copy link
Contributor

Choose a reason for hiding this comment

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

This makes me wonder about those who hard-code the metadata_url in a CI/CD flow or elsewhere, where this may break for them now. Should we add validation coverage for invalid resource values (i.e. non-HTTP(S) scheme or missing host) so startup fails fast?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, totally fair concern! Added a scheme check that rejects non-HTTP resource URLs at startup.

Copy link
Contributor

@gocamille gocamille left a comment

Choose a reason for hiding this comment

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

This is great thank you @DaleSeo !

@DaleSeo DaleSeo merged commit 874a12e into main Mar 4, 2026
18 checks passed
@DaleSeo DaleSeo deleted the AMS-382 branch March 4, 2026 14:14
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.

Config for .well-known/oauth-protected-resource does not provide resource path for redirects

2 participants