Skip to content

Support full OAuth 2.1 resource server security (DPoP, introspection, error signaling) in transport security hooks #887

@muralx

Description

@muralx

Expected Behavior

A resource server implementator should be able to, in a single authentication flow:

  • Validate sender-constrained tokens such as DPoP (RFC 9449), which require the HTTP method and request URL in addition to headers
  • Return proper HTTP 401/403 responses with WWW-Authenticate challenges (RFC 6750 §3) when validation fails
  • Pass verified claims into the McpTransportContext for use by tool handlers
  • Perform expensive operations like token introspection (RFC 7662) exactly once per request

Current Behavior

The transport security model splits authentication into two hooks, each covering part of what we find is needed for a complete OAuth 2.1 flow:

   
  ┌─────────────────────────────┬─────────────────┬─────────┐                                                                                                                                                                                                                   
  │         Capability          │ validateHeaders │ extract │
  ├─────────────────────────────┼─────────────────┼─────────┤
  │ HTTP method & URL           │ No              │ Yes     │
  ├─────────────────────────────┼─────────────────┼─────────┤
  │ Can return 401/403          │ Yes             │ No      │
  ├─────────────────────────────┼─────────────────┼─────────┤
  │ Can store claims in context │ No              │ Yes     │
  └─────────────────────────────┴─────────────────┴─────────┘           
                                                                                                                                                                                                        
   
  @FunctionalInterface                                                                                                                                                                                                                                                          
  public interface ServerTransportSecurityValidator {
      void validateHeaders(Map<String, List<String>> headers)
          throws ServerTransportSecurityException;
  }

  public interface McpTransportContextExtractor<T> {                                                                                                                                                                                                                            
      McpTransportContext extract(T request);
  }                                                                                                                                                                                                                                                                             

It seems these capabilities are all needed together but currently live in separate hooks:

  1. validateHeaders doesn't have access to HTTP method and URL — DPoP proof validation (RFC 9449 §4.3) requires htm (method) and htu (URL), so we can't fully validate DPoP-bound tokens at this stage.
  2. extract doesn't have a way to signal authentication errors — When we need to defer validation to extract (because validateHeaders lacked sufficient context), authentication failures end up surfacing as 500s or unstructured exceptions rather than proper 401/403
    responses.
  3. Validated claims can't flow from validation to context — validateHeaders returns void, so even after successful validation there's no way to pass the resulting claims into the McpTransportContext without external coordination.

Context

We are integrating OAuth 2.1in our MCP servers with JWT validation, token introspection, and DPoP sender-constraining. With the current interface design, we've had to resort to workarounds like ThreadLocal caching between the two hooks, or accepting duplicate verification and introspection calls per request. These work, but feel like they could be improved at the framework level.

References:

  • RFC 9449 — DPoP
  • RFC 6750 — Bearer Token Usage
  • RFC 7662 — Token Introspection
  • MCP SDK version: 1.0.0 (io.modelcontextprotocol.sdk:mcp-core)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions