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

Open
#19,342 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

status: waiting-for-triage type: bug
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:

  1. OAuth 2.0 Authorization Server Metadata with path insertion: https://auth.example.com/.well-known/oauth-authorization-server/tenant1
  2. OpenID Connect Discovery 1.0 with path insertion: https://auth.example.com/.well-known/openid-configuration/tenant1
  3. 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

  1. 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).
  2. Start the server.
  3. GET http://host:8080/.well-known/oauth-authorization-server/tenant1 — returns 200 (OAuth metadata, path insertion).
  4. GET http://host:8080/tenant1/.well-known/openid-configuration — returns 200 (OIDC metadata, path append).
  5. 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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.