The search is over. Easy OAuth 2.0 proxy for MCP servers.
flowchart TB
User[๐ค User Browser<br/>Claude Web Page]
AI[๐ค AI Client<br/>Claude Web Server]
RP[๐ Reverse Proxy<br/>e.g. nginx]
Proxy[๐ก๏ธ mcp-oauth2-proxy<br/>Authorization Server]
IdP[๐ Identity Provider<br/>Google/GitHub/Microsoft]
MCP1[๐ฆ MCP Server 1<br/>host: server1.example.com]
MCP2[๐ฆ MCP Server 2<br/>host: server2.example.com]
%% User interactions
User -.-> AI
User -.-> IdP
User -.-> RP
%% AI Client to services via Reverse Proxy
AI --> RP
RP --> Proxy
RP --> MCP1
RP --> MCP2
%% Authentication flow
Proxy -.-> IdP
%% Styling
classDef userStyle fill:#e1f5fe,stroke:#01579b,stroke-width:2px,color:#000
classDef aiStyle fill:#f3e5f5,stroke:#4a148c,stroke-width:2px,color:#000
classDef proxyStyle fill:#e8f5e8,stroke:#1b5e20,stroke-width:2px,color:#000
classDef idpStyle fill:#fff3e0,stroke:#e65100,stroke-width:2px,color:#000
classDef mcpStyle fill:#fce4ec,stroke:#880e4f,stroke-width:2px,color:#000
classDef rpStyle fill:#f1f8e9,stroke:#33691e,stroke-width:2px,color:#000
class User userStyle
class AI aiStyle
class Proxy proxyStyle
class IdP idpStyle
class MCP1,MCP2 mcpStyle
class RP rpStyle
The mcp-oauth2-proxy exposes the following HTTP endpoints:
/authenticate
- Token validation endpoint used by reverse proxy
Authorization: Bearer <jwt-token>
- JWT issued by mcp-oauth2-proxyWWW-Authenticate: Bearer realm="mcp-oauth2-proxy", resource_metadata="<base-url>/.well-known/oauth-protected-resource"
/.well-known/oauth-protected-resource
- OAuth 2.0 Protected Resource metadata/.well-known/oauth-authorization-server
- OAuth 2.0 Authorization Server metadata/register
- OAuth 2.0 Dynamic Client Registration/authorize
- OAuth 2.0 Authorization endpoint (PKCE required)/callback
- OAuth 2.0 Authorization callback/token
- OAuth 2.0 Token exchange endpoint/.well-known/openid-configuration
- OpenID Connect Discovery document
issuer
- The authorization serverโs issuer identifier URLjwks_uri
- URL of the JSON Web Key Set containing signing keysid_token_signing_alg_values_supported
- Supported signing algorithms (RS256)/openid/v1/jwks
- JSON Web Key Set (JWKS) for token verification
keys
- Array of JWK objects containing RSA public keys for token verificationNote: The signing keys live only in memory and are rotated hourly. To force an immediate key rotation, simply restart the proxy. This will invalidate all existing tokens.
MCP servers can advertise scopes through the tools/list
MCP request. If the response
contains a _meta.scopes
field with a list of scopes, the user will be presented
with a consent screen during the OAuth2 authorization flow to choose which scopes
should be granted to the issued token.
For example, if the MCP server responds with:
[
{
"name": "toolbox:read_only",
"description": "Allow all read-only toolbox operations.",
"tools": [
"get_resource",
"list_resources"
]
},
{
"name": "toolbox:read_write",
"description": "Allow all toolbox operations.",
"tools": [
"get_resource",
"list_resources",
"create_resource",
"update_resource",
"delete_resource"
]
},
{
"name": "toolbox:get_resource",
"description": "Allow getting a resource.",
"tools": [
"get_resource"
]
},
{
"name": "toolbox:list_resources",
"description": "Allow listing resources.",
"tools": [
"list_resources"
]
},
{
"name": "toolbox:create_resource",
"description": "Allow creating resources.",
"tools": [
"create_resource"
]
},
{
"name": "toolbox:update_resource",
"description": "Allow updating resources.",
"tools": [
"update_resource"
]
},
{
"name": "toolbox:delete_resource",
"description": "Allow deleting resources.",
"tools": [
"delete_resource"
]
}
]
Users will see a consent screen like this:
A container image is distributed via GitHub Container Registry and signed with keyless Cosign:
ghcr.io/matheuscscp/mcp-oauth2-proxy
An OCI Helm chart is distributed via GitHub Container Registry and signed with keyless Cosign:
helm install mcp-oauth2-proxy oci://ghcr.io/matheuscscp/mcp-oauth2-proxy/charts/mcp-oauth2-proxy \
--set provider.name=google \
--set provider.clientID=your-client-id \
--set provider.clientSecret=your-client-secret
The main configuration options are:
provider.name
: The identifier of the Identity Provider.provider.clientID
: OAuth2 client ID from your IdP.provider.clientSecret
: OAuth2 client secret from your IdP.provider.allowedEmailDomains
(optional): List of Go regular expressions for allowed email domains.proxy.hosts
: List of MCP server hosts to proxy requests for.proxy.hosts[].host
: The HTTP Host header identifying the MCP server.proxy.hosts[].endpoint
(optional): The internal endpoint where the MCP server can be reached by the proxy. Used for listing tools and scopes.proxy.disableConsentScreen
(optional): Disable the permissions consent screen. Defaults to false
.proxy.allowedRedirectURLs
(optional): List of Go regular expressions for allowed redirect URLs.proxy.cors
(optional): Enable CORS support. Defaults to false
.networkPolicy.create
(optional): Create a NetworkPolicy to restrict access to the proxy. Defaults to true
.ingress.enabled
(optional): Enable ingress for external access. Defaults to false
.podMonitor.enabled
(optional): Enable Prometheus monitoring. Defaults to false
.For all the available options, see values.yaml.
To integrate with ingress-nginx, configure the mcp-oauth2-proxy Helm chart to enable ingress
by specifying a host configuration in the value proxy.hosts
, then create Ingress resources
for each MCP server that requires authentication.
Example of Ingress resource for an MCP server:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-mcp-server
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
# Only the auth-url annotation is needed for mcp-oauth2-proxy
nginx.ingress.kubernetes.io/auth-url: https://$host/authenticate
spec:
ingressClassName: nginx
tls:
- hosts:
- my-mcp.example.com
secretName: my-mcp-server-tls
rules:
- host: my-mcp.example.com
http:
paths:
- path: /mcp
pathType: ImplementationSpecific
backend:
service:
name: my-mcp-server
port:
name: http
The key difference from traditional oauth2-proxy integration is that mcp-oauth2-proxy only requires the
auth-url
annotation. The /authenticate
endpoint handles token validation. If the token is not present
or is invalid, it returns 401 with the WWW-Authenticate
header pointing to the authorization server
metadata endpoints, according to the MCP specification.
Donโt see the provider you need? Just open an issue to let me know!