Bug Description
When the well-known fallback DOES happen, the root well-known URL is built on the wrong base: the resource-server origin is used instead of the authorization-server issuer URL. When the AS lives on a different host than the resource, the fallback fetches an unrelated metadata document.
Steps to Reproduce
Repro (Superhuman): resource https://docs.superhuman.com/apis/mcp
- Resource metadata at
https://docs.superhuman.com/.well-known/oauth-protected-resource/apis/mcp correctly lists authorization_servers: ["https://id.superhuman.com"].
- But the AS-metadata fallback fetches
https://docs.superhuman.com/.well-known/oauth-authorization-server (resource host) instead of the id.superhuman.com equivalent.
- That document is for a DIFFERENT service (issuer
https://tokens.grammarly.com), so the client sends users to tokens.grammarly.com's authorize endpoint with a client registered at id.superhuman.com → 403 on the consent page.
Expected Behavior
The fallback should stay on the authorization-server host (https://id.superhuman.com/.well-known/oauth-authorization-server, which returns 200).
Actual Behavior
The fallback URL is constructed as new URL('/.well-known/' + type, resourceUrl) instead of using the authorizationServerUrl base, so it fetches another service's metadata document.
Environment
- Discovered via mcp-hub 4.2.1 (npm, node 24, macOS) in front of remote OAuth MCP servers.
- Local workaround confirmed: switching the fallback base from the resource URL to the authorization-server URL fixes it.
Related
Possibly related to #1716 (wrong redirect URL when AS discovery fails for non-root paths) — this is the fallback-URL construction itself picking the wrong host.
Bug Description
When the well-known fallback DOES happen, the root well-known URL is built on the wrong base: the resource-server origin is used instead of the authorization-server issuer URL. When the AS lives on a different host than the resource, the fallback fetches an unrelated metadata document.
Steps to Reproduce
Repro (Superhuman): resource
https://docs.superhuman.com/apis/mcphttps://docs.superhuman.com/.well-known/oauth-protected-resource/apis/mcpcorrectly listsauthorization_servers: ["https://id.superhuman.com"].https://docs.superhuman.com/.well-known/oauth-authorization-server(resource host) instead of theid.superhuman.comequivalent.https://tokens.grammarly.com), so the client sends users to tokens.grammarly.com's authorize endpoint with a client registered at id.superhuman.com → 403 on the consent page.Expected Behavior
The fallback should stay on the authorization-server host (
https://id.superhuman.com/.well-known/oauth-authorization-server, which returns 200).Actual Behavior
The fallback URL is constructed as
new URL('/.well-known/' + type, resourceUrl)instead of using the authorizationServerUrl base, so it fetches another service's metadata document.Environment
Related
Possibly related to #1716 (wrong redirect URL when AS discovery fails for non-root paths) — this is the fallback-URL construction itself picking the wrong host.