OAuth Configuration Reference - WunderGraph
Configuration Options
| Option | Description | Default |
|---|---|---|
oauth.enabled |
Enable OAuth 2.1 / JWKS-based authentication for the MCP server | false |
oauth.authorization_server_url |
Base URL of the OAuth 2.0 authorization server. Advertised via the RFC 9728 metadata endpoint so clients can discover authorization endpoints. | - |
oauth.scope_challenge_include_token_scopes |
When true, includes the token’s existing scopes in the scope parameter of 403 responses. Works around MCP SDK scope accumulation bugs. See Scope Challenge Behavior. |
false |
oauth.max_scope_combinations |
Maximum scope combinations computed per operation. Raise for schemas with many overlapping @requiresScopes. |
2048 |
oauth.scopes.initialize |
Scopes required for all HTTP requests (checked before JSON-RPC parsing). This is the baseline scope needed to establish an MCP connection. | [] |
oauth.scopes.tools_list |
Scopes required for the tools/list MCP method. |
[] |
oauth.scopes.tools_call |
Scopes required for the tools/call MCP method (any tool invocation). Per-tool and built-in tool scopes are enforced additively. |
[] |
oauth.scopes.execute_graphql |
Scopes required to call the execute_graphql built-in tool. Additive to tools_call. Only relevant when enable_arbitrary_operations is true. |
[] |
oauth.scopes.get_operation_info |
Scopes required to call the get_operation_info built-in tool. Additive to tools_call. |
[] |
oauth.scopes.get_schema |
Scopes required to call the get_schema built-in tool. Additive to tools_call. Only relevant when expose_schema is true. |
[] |
oauth.jwks |
List of JWKS providers for JWT verification. Supports remote JWKS URLs or symmetric secrets. | [] |
JWKS Configuration
The oauth.jwks array configures one or more JWKS providers for JWT verification.
Remote JWKS URL
oauth:
jwks:
- url: 'https://auth.example.com/.well-known/jwks.json'
audiences:
- 'https://mcp.example.com'
algorithms:
- 'RS256'
- 'ES256'
refresh_interval: '1m' # How often to refresh the key set
| Field | Description | Default |
|---|---|---|
url |
URL of the JWKS endpoint | (required) |
audiences |
Allowed JWT aud claim values |
(any) |
algorithms |
Allowed signing algorithms (RS256, ES256, PS256, EdDSA, etc.) | (all) |
refresh_interval |
How often to refresh the JWKS key set | 1m |
Symmetric Secret
For development or testing, you can use a shared symmetric secret instead of a remote JWKS endpoint:
oauth:
jwks:
- secret: 'your-shared-secret'
symmetric_algorithm: 'HS256' # HS256, HS384, or HS512. For other algorithms, use a remote JWKS URL.
header_key_id: 'my-key-id'
Environment Variables
| Environment Variable | Configuration Path |
|---|---|
MCP_OAUTH_ENABLED |
mcp.oauth.enabled |
MCP_OAUTH_AUTHORIZATION_SERVER_URL |
mcp.oauth.authorization_server_url |
MCP_OAUTH_SCOPE_CHALLENGE_INCLUDE_TOKEN_SCOPES |
mcp.oauth.scope_challenge_include_token_scopes |
MCP_OAUTH_MAX_SCOPE_COMBINATIONS |
mcp.oauth.max_scope_combinations |
HTTP Error Responses
401 Unauthorized
Returned when the token is missing, invalid, expired, or signature verification fails.
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer realm="mcp",
scope="mcp:connect",
resource_metadata="https://mcp.example.com/.well-known/oauth-protected-resource/mcp"
403 Forbidden
Returned when the token is valid but lacks required scopes. The exact scope parameter depends on which level of enforcement rejected the request:
Method-level rejection (e.g., missing tools_call scopes):
HTTP/1.1 403 Forbidden
WWW-Authenticate: Bearer error="insufficient_scope",
scope="mcp:tools:execute",
resource_metadata="https://mcp.example.com/.well-known/oauth-protected-resource/mcp",
error_description="missing required scopes: mcp:tools:execute"
Example response for protected resource metadata:
{
"resource": "https://mcp.example.com",
"authorization_servers": ["https://auth.example.com"],
"bearer_methods_supported": ["header"],
"resource_documentation": "https://mcp.example.com/mcp",
"scopes_supported": [
"mcp:connect",
"mcp:tools:execute",
"mcp:tools:read",
"read:all",
"read:employee",
"read:fact",
"read:private"
]
}
Startup Validation
The router performs startup validation when OAuth is enabled:
- If
oauth.jwksis empty, the router exits with a fatal error to prevent starting an unprotected endpoint. - If
server.base_urlis empty, the router exits with a fatal error because it is required for RFC 9728 metadata discovery.
Full Configuration Example
mcp:
enabled: true
server:
listen_addr: '0.0.0.0:5025'
base_url: 'https://mcp.example.com'
graph_name: 'my-graph'
exclude_mutations: true
enable_arbitrary_operations: true # Enables execute_graphql tool
expose_schema: true # Enables get_schema tool
oauth:
enabled: true
authorization_server_url: 'https://auth.example.com'
scope_challenge_include_token_scopes: false # Set to true for MCP clients with scope accumulation bugs
scopes:
initialize:
- 'mcp:connect'
tools_list:
- 'mcp:tools:read'
tools_call:
- 'mcp:tools:execute'
# Built-in tool scopes (additive to tools_call)
execute_graphql:
- 'mcp:graphql:execute'
get_schema:
- 'mcp:schema:read'
get_operation_info:
- 'mcp:ops:read'
jwks:
- url: 'https://auth.example.com/.well-known/jwks.json'
audiences:
- 'https://mcp.example.com'
algorithms:
- 'RS256'
refresh_interval: '1m'
storage:
provider_id: 'mcp'
session:
stateless: true
storage_providers:
file_system:
- id: 'mcp'
path: 'operations'