This is an automated email from the ASF dual-hosted git repository.

epugh pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/solr-mcp.git


The following commit(s) were added to refs/heads/main by this push:
     new 74e9a9a  fix(security): enable JWT audience validation and declare MCP 
resource path (#123)
74e9a9a is described below

commit 74e9a9ad3274e6c3f784b13332d52c3ad3a527b0
Author: Aditya Parikh <[email protected]>
AuthorDate: Fri May 8 16:56:26 2026 -0400

    fix(security): enable JWT audience validation and declare MCP resource path 
(#123)
    
    Per the MCP Authorization specification, MCP servers MUST validate that
    tokens were specifically issued for them — otherwise any valid JWT from
    the same IdP for any sibling application is accepted, enabling
    token-confusion pivots (CWE-345).
    
    Wires the existing McpServerOAuth2Configurer with:
      - resourcePath("/mcp") — declares the canonical resource indicator
        surfaced via OAuth 2.0 Protected Resource Metadata (RFC 9728), which
        MCP clients use to discover the authorization server.
      - validateAudienceClaim(true) — enforces that the JWT "aud" claim
        matches that resource indicator (RFC 8707).
    
    Operators must configure their IdP to populate "aud" with the MCP
    server's URL. The application-http.properties comment block documents
    the required setup for Auth0, Okta, and Keycloak (which does not yet
    honor RFC 8707 `resource=` natively and needs an Audience protocol
    mapper on a client scope).
    
    Refs:
    - MCP Authorization spec, "Token Audience Binding and Validation":
      
https://modelcontextprotocol.io/specification/2025-06-18/basic/authorization
    - RFC 8707 (Resource Indicators):
      https://www.rfc-editor.org/rfc/rfc8707.html
    - RFC 9728 (Protected Resource Metadata):
      https://www.rfc-editor.org/rfc/rfc9728.html
    - Keycloak MCP integration docs (Audience mapper workaround):
      https://www.keycloak.org/securing-apps/mcp-authz-server
    
    Signed-off-by: adityamparikh <[email protected]>
    Co-authored-by: Claude Opus 4.7 (1M context) <[email protected]>
---
 .../mcp/server/security/HttpSecurityConfiguration.java    | 15 +++++++++++++--
 src/main/resources/application-http.properties            | 12 ++++++++++++
 2 files changed, 25 insertions(+), 2 deletions(-)

diff --git 
a/src/main/java/org/apache/solr/mcp/server/security/HttpSecurityConfiguration.java
 
b/src/main/java/org/apache/solr/mcp/server/security/HttpSecurityConfiguration.java
index ac0c3ae..61f5663 100644
--- 
a/src/main/java/org/apache/solr/mcp/server/security/HttpSecurityConfiguration.java
+++ 
b/src/main/java/org/apache/solr/mcp/server/security/HttpSecurityConfiguration.java
@@ -50,9 +50,20 @@ class HttpSecurityConfiguration {
                                        
auth.requestMatchers("/mcp").permitAll();
                                        auth.anyRequest().authenticated();
                                })
-                               // Configure OAuth2 on the MCP server
+                               // Configure OAuth2 on the MCP server.
+                               //
+                               // resourcePath: declares "/mcp" as the 
canonical resource indicator
+                               // for OAuth 2.0 Protected Resource Metadata 
(RFC 9728), which is what
+                               // MCP clients use to discover the 
authorization server.
+                               //
+                               // validateAudienceClaim: per the MCP 
Authorization specification, MCP
+                               // servers MUST validate that tokens were 
specifically issued for them.
+                               // The audience is matched against the resource 
indicator (RFC 8707)
+                               // configured above. The IdP must populate the 
JWT "aud" claim
+                               // accordingly — see docs/security/http.md for 
IdP configuration notes.
                                
.with(McpServerOAuth2Configurer.mcpServerOAuth2(),
-                                               mcpAuthorization -> 
mcpAuthorization.authorizationServer(issuerUrl))
+                                               mcpAuthorization -> 
mcpAuthorization.authorizationServer(issuerUrl).resourcePath("/mcp")
+                                                               
.validateAudienceClaim(true))
                                // MCP inspector
                                .cors(cors -> 
cors.configurationSource(corsConfigurationSource())).csrf(CsrfConfigurer::disable)
                                .build();
diff --git a/src/main/resources/application-http.properties 
b/src/main/resources/application-http.properties
index 04504c0..1364348 100644
--- a/src/main/resources/application-http.properties
+++ b/src/main/resources/application-http.properties
@@ -10,6 +10,18 @@ spring.docker.compose.enabled=true
 # For Auth0: https://<your-auth0-domain>/.well-known/openid-configuration
 # For Keycloak: https://<keycloak-host>/realms/<realm-name>
 # For Okta: 
https://<your-okta-domain>/oauth2/default/.well-known/openid-configuration
+#
+# Audience validation: when http.security.enabled=true, the MCP server enforces
+# that incoming JWTs carry an "aud" claim matching its canonical resource URI
+# (per RFC 8707 / the MCP Authorization specification).  The IdP must be
+# configured to populate "aud" accordingly:
+#   * Auth0   - pass `audience=<MCP server URL>` on the auth request; Auth0
+#               reflects it into "aud" automatically.
+#   * Okta    - configure the audience on the Authorization Server.
+#   * Keycloak - add an "Audience" protocol mapper on a client scope and set
+#               `Included Custom Audience` to the MCP server URL (Keycloak does
+#               not yet honor RFC 8707 `resource=` natively, see
+#               docs/security/http.md).
 
spring.security.oauth2.resourceserver.jwt.issuer-uri=${OAUTH2_ISSUER_URI:https://your-auth0-domain.auth0.com/}
 # Security toggle - HTTP mode is secured by default. Set 
HTTP_SECURITY_ENABLED=false
 # to bypass OAuth2 authentication for local development only. Disabling 
security

Reply via email to