Description
Authorization server metadata discovery rejects a valid path-based issuer when the issuer ends with a trailing slash.
For example, given the authorization server issuer:
https://auth.example.com/tenant/
RFC 8414 path-insertion discovery uses:
https://auth.example.com/.well-known/oauth-authorization-server/tenant
If that endpoint returns metadata containing the original issuer:
{
"issuer": "https://auth.example.com/tenant/",
"authorization_endpoint": "https://auth.example.com/tenant/authorize",
"token_endpoint": "https://auth.example.com/tenant/token"
}
rmcp rejects it with an issuer mismatch equivalent to:
expected: https://auth.example.com/tenant
received: https://auth.example.com/tenant/
Root cause
generate_discovery_urls() correctly removes the issuer path's trailing slash when constructing the RFC 8414 discovery URL. However, the original issuer is not retained.
After fetching the document, expected_issuer_for_authorization_metadata_url() reconstructs the expected issuer from that discovery URL. This reverse transformation is lossy: both these issuers produce the same discovery URL:
https://auth.example.com/tenant
https://auth.example.com/tenant/
The reconstructed expected issuer therefore becomes https://auth.example.com/tenant, even when the original issuer was https://auth.example.com/tenant/.
issuer_identifiers_match() intentionally treats only root-path trailing slashes as equivalent, so the path-based values fail validation. The strict comparison itself should remain unchanged because these are distinct issuer identifiers; the problem is that the expected identifier was reconstructed from a lossy representation.
Expected behavior
Metadata whose issuer exactly matches the original authorization server issuer should be accepted, including a trailing slash on a non-root path.
Suggested fix
Carry the expected issuer together with each generated discovery URL, deriving it from the original authorization server URL. Validate metadata against that retained value instead of reconstructing it from the discovery URL.
This preserves strict issuer validation while avoiding the lossy reverse transformation.
Regression context
Issuer validation was introduced in #996 as the fix for #983. The validation is correct, but the current implementation does not preserve enough information to validate this trailing-slash case correctly.
Description
Authorization server metadata discovery rejects a valid path-based issuer when the issuer ends with a trailing slash.
For example, given the authorization server issuer:
RFC 8414 path-insertion discovery uses:
If that endpoint returns metadata containing the original issuer:
{ "issuer": "https://auth.example.com/tenant/", "authorization_endpoint": "https://auth.example.com/tenant/authorize", "token_endpoint": "https://auth.example.com/tenant/token" }rmcp rejects it with an issuer mismatch equivalent to:
Root cause
generate_discovery_urls()correctly removes the issuer path's trailing slash when constructing the RFC 8414 discovery URL. However, the original issuer is not retained.After fetching the document,
expected_issuer_for_authorization_metadata_url()reconstructs the expected issuer from that discovery URL. This reverse transformation is lossy: both these issuers produce the same discovery URL:https://auth.example.com/tenanthttps://auth.example.com/tenant/The reconstructed expected issuer therefore becomes
https://auth.example.com/tenant, even when the original issuer washttps://auth.example.com/tenant/.issuer_identifiers_match()intentionally treats only root-path trailing slashes as equivalent, so the path-based values fail validation. The strict comparison itself should remain unchanged because these are distinct issuer identifiers; the problem is that the expected identifier was reconstructed from a lossy representation.Expected behavior
Metadata whose
issuerexactly matches the original authorization server issuer should be accepted, including a trailing slash on a non-root path.Suggested fix
Carry the expected issuer together with each generated discovery URL, deriving it from the original authorization server URL. Validate metadata against that retained value instead of reconstructing it from the discovery URL.
This preserves strict issuer validation while avoiding the lossy reverse transformation.
Regression context
Issuer validation was introduced in #996 as the fix for #983. The validation is correct, but the current implementation does not preserve enough information to validate this trailing-slash case correctly.