docs/features/oauth-authentication.md
MCPProxy supports OAuth 2.1 authentication with PKCE for secure authentication to remote MCP servers.
OAuth authentication is used when connecting to MCP servers that require authorization, such as:
{
"mcpServers": [
{
"name": "github-server",
"url": "https://api.github.com/mcp",
"protocol": "http",
"oauth": {
"client_id": "your-client-id",
"scopes": ["repo", "user"]
},
"enabled": true
}
]
}
| Option | Type | Description |
|---|---|---|
client_id | string | OAuth client identifier (uses Dynamic Client Registration if empty) |
client_secret | string | OAuth client secret (optional, can reference secure storage) |
redirect_uri | string | OAuth redirect URI (auto-generated if not provided) |
scopes | array | Requested OAuth scopes |
pkce_enabled | boolean | PKCE is always enabled for security; this flag is currently ignored |
extra_params | object | Additional authorization parameters (e.g., RFC 8707 resource) |
Note: OAuth authorization and token endpoints are automatically discovered from the server's OAuth metadata (RFC 8414 .well-known/oauth-authorization-server), not configured manually.
For OAuth providers that require additional parameters (like RFC 8707 resource indicators):
{
"oauth": {
"client_id": "your-client-id",
"client_secret": "your-client-secret",
"scopes": ["read", "write"],
"extra_params": {
"audience": "https://api.example.com",
"resource": "https://api.example.com"
}
}
}
MCPProxy automatically refreshes tokens before expiration:
When an OAuth-protected server has no usable token, the Web UI does not render it as a generic red "Server Error". Instead it surfaces a calm, actionable Sign-in state:
mcpproxy auth login) and a link to this page. No "file a bug" prompt is
shown for OAuth states ā signing in is the fix.mcpproxy auth login --server=github-server
mcpproxy auth status
mcpproxy auth login --server=github-server --log-level=debug
MCPProxy supports automatic RFC 8707 resource parameter detection for OAuth providers that require it:
{
"oauth": {
"client_id": "your-client-id",
"extra_params": {
"resource": "https://api.example.com"
}
}
}
For providers like Runlayer, MCPProxy can auto-detect the resource parameter from the server's OAuth metadata.
Tokens are stored securely using the system keyring:
| Platform | Storage |
|---|---|
| macOS | Keychain |
| Windows | Credential Manager |
| Linux | Secret Service (libsecret) |
MCPProxy provides structured error responses for OAuth failures, making it easier to diagnose and fix authentication issues.
| Error Type | Description | Common Causes |
|---|---|---|
client_id_required | OAuth client ID is missing | Server requires pre-registered client, DCR not supported |
dcr_failed | Dynamic Client Registration failed | Server rejected registration, permission denied |
metadata_discovery_failed | Could not discover OAuth metadata | Server unreachable, missing .well-known endpoints |
code_flow_failed | Authorization code flow failed | User denied, invalid redirect, network issues |
When OAuth fails, the CLI displays rich error information:
ā OAuth Error: dcr_failed
Server: github-server
Message: Dynamic Client Registration failed: 403 Forbidden
Suggestion: Check if the OAuth server requires pre-registered clients
š Debug:
Server logs: mcpproxy upstream logs github-server
Activity log: mcpproxy activity list --request-id req-xyz-123
Request ID: req-xyz-123
Correlation ID: a1b2c3d4e5f6789012345678
The REST API returns structured OAuthFlowError responses:
{
"success": false,
"error_type": "dcr_failed",
"server_name": "github-server",
"message": "Dynamic Client Registration failed: 403 Forbidden",
"suggestion": "Check if the OAuth server requires pre-registered clients",
"correlation_id": "a1b2c3d4e5f6789012345678",
"request_id": "req-xyz-123",
"details": {
"metadata": {
"status": "ok",
"protected_resource_url": "https://api.example.com/.well-known/oauth-protected-resource"
},
"dcr": {
"attempted": true,
"status": "failed",
"error": "403 Forbidden"
}
}
}
Use the request_id from error responses to find related logs:
# Find activity records for a specific request
mcpproxy activity list --request-id req-xyz-123
# View server-specific logs
mcpproxy upstream logs github-server --tail 50
# Run in headless mode with manual URL copy
HEADLESS=true mcpproxy auth login --server=github-server
auth statusVerify the requested scopes are valid for the OAuth provider:
mcpproxy auth login --server=github-server --log-level=debug
Ensure the OAuth server URLs are accessible:
curl -I https://auth.example.com/.well-known/oauth-authorization-server