spring-projects / spring-projects/spring-security
OidcProviderConfigurationEndpointFilter (multi-issuer) only matches the path-append discovery location, not path-insertion — asymmetric with OAuth2AuthorizationServerMetadataEndpointFilter and breaks MCP discovery priority #2
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 9.6k
- Forks
- 6.3k
- Avg merge
- 2d 11h
- Merged PRs (30d)
- 52
Description
Describe the bug
When AuthorizationServerSettings.multipleIssuersAllowed(true) is set, the two metadata endpoint filters use opposite and incompatible well-known URL shapes for an issuer that has a path component, so only one of
the two OpenID Connect discovery locations defined for path-bearing issuers is served.
OAuth2AuthorizationServerMetadataEndpointFilter matches the path-insertion shape /.well-known/oauth-authorization-server/** (well-known segment first, issuer path appended):
https://github.com/spring-projects/spring-security/blob/43f958e0587e07bcb322194ce2acf9ad921a5b88/oauth2/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/web/OAuth2A
uthorizationServerMetadataEndpointFilter.java#L131
OidcProviderConfigurationEndpointFilter matches only the path-append shape /**/.well-known/openid-configuration (issuer path first, well-known segment last):
https://github.com/spring-projects/spring-security/blob/43f958e0587e07bcb322194ce2acf9ad921a5b88/oauth2/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/oidc/web/Oi
dcProviderConfigurationEndpointFilter.java#L136
As a result, for an issuer such as https://host/tenant1:
- https://host/.well-known/oauth-authorization-server/tenant1 returns 200 (OAuth, path insertion)
- https://host/.well-known/openid-configuration/tenant1 returns 404 (OIDC, path insertion) — not served
- https://host/tenant1/.well-known/openid-configuration returns 200 (OIDC, path append)
This asymmetry breaks interoperability with the Model Context Protocol (MCP) authorization spec, which requires clients to try the OIDC path-insertion location and lists it ahead of the append location. From
https://modelcontextprotocol.io/specification/2025-11-25/basic/authorization (section "Authorization Server Metadata Discovery"):
"For issuer URLs with path components (e.g., https://auth.example.com/tenant1), clients MUST try endpoints in the following priority order:
- OAuth 2.0 Authorization Server Metadata with path insertion: https://auth.example.com/.well-known/oauth-authorization-server/tenant1
- OpenID Connect Discovery 1.0 with path insertion: https://auth.example.com/.well-known/openid-configuration/tenant1
- OpenID Connect Discovery 1.0 path appending: https://auth.example.com/tenant1/.well-known/openid-configuration"
That same MCP section states the approach is based on RFC 8414 Section 3.1 ("Authorization Server Metadata Request") and RFC 8414 Section 5 ("Compatibility Notes") for OpenID Connect Discovery 1.0 interoperability.
So priority #2 — the OIDC path-insertion location — is exactly what OidcProviderConfigurationEndpointFilter does not serve, while the OAuth filter already serves the analogous insertion location for its own
document.
To Reproduce
- Configure a SecurityFilterChain that registers OAuth2AuthorizationServerMetadataEndpointFilter and OidcProviderConfigurationEndpointFilter, with
AuthorizationServerSettings.builder().multipleIssuersAllowed(true).build() available on the per-request AuthorizationServerContext (issuer e.g. http://host:8080/tenant1). - Start the server.
- GET http://host:8080/.well-known/oauth-authorization-server/tenant1 — returns 200 (OAuth metadata, path insertion).
- GET http://host:8080/tenant1/.well-known/openid-configuration — returns 200 (OIDC metadata, path append).
- GET http://host:8080/.well-known/openid-configuration/tenant1 — returns 404 (OIDC metadata, path insertion), even though an MCP client following the spec's priority order tries this URL before the append form.
Expected behavior
In multi-issuer mode, OidcProviderConfigurationEndpointFilter should also serve the OIDC path-insertion location /.well-known/openid-configuration/**, symmetric with OAuth2AuthorizationServerMetadataEndpointFilter,
so that GET https://host/.well-known/openid-configuration/tenant1 returns the same document as the path-append location. Alternatively (or additionally), the filter should expose a way to configure its
RequestMatcher; it is currently final with a private final RequestMatcher and only setProviderConfigurationCustomizer is available, so applications cannot add the insertion location without wrapping/rewriting the
request.
The document body itself needs no change: the filter builds it solely from AuthorizationServerContextHolder.getContext().getIssuer(), so only the request matching (and the corresponding multi-issuer issuer
resolution, which must recognize that for the insertion shape the issuer path follows the well-known segment rather than preceding it) needs to handle both shapes.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with OidcProviderConfigurationEndpointFilter.java and compare its request matching and issuer resolution with OAuth2AuthorizationServerMetadataEndpointFilter.java, especially the linked lines. Reproduce both path shapes in multi-issuer mode, then verify that the insertion and append OIDC locations return the same metadata document.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java, spring
- Domain
- api, security
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 68/100