Skip to content

fhswf/mcp-auth-middleware

Repository files navigation

mcp-auth-middleware

JWE authentication middleware for HTTP MCP servers. Encrypt user data end-to-end so that only your MCP server can read it.

What it does

mcp-auth-middleware gives your MCP server two things:

  1. A middleware that decrypts a JWE Bearer token, enforces configured JWT scopes, and exposes the authenticated user's claims via get_user().
  2. A CLI (mcp-auth-middleware) that generates RSA key pairs in JWKS format, outputs Kubernetes Secret YAML, and securely deletes local keys when you're done.

The middleware also publishes:

  • /.well-known/jwks.json for public key discovery
  • /.well-known/openid-configuration for OpenID discovery

Installation

pip install mcp-auth-middleware

Testing

python -m pip install -r requirements.txt
python -m pip install -e .
pytest --cov=mcp_auth_middleware --cov-report=term-missing --cov-fail-under=80

Quick start

1. Generate keys

mcp-auth-middleware generate

This writes:

.keys/mcp-private.json
.keys/mcp-public.json

2. Configure the private key

MCP_KEY_FILE_PATH=.keys/mcp-private.json

3. Add the middleware

import uvicorn
from fastmcp import FastMCP

from mcp_auth_middleware import JWKSAuthMiddleware, get_user

mcp = FastMCP("My Server")

required_scopes = [
    {"scope": "name"},
    {"scope": "email"},
]


@mcp.tool()
def whoami() -> str:
    user = get_user()
    return f"Hello, {user.name}!"


app = mcp.http_app()
app.add_middleware(JWKSAuthMiddleware, scopes=required_scopes)

if __name__ == "__main__":
    uvicorn.run(app, host="0.0.0.0", port=8000)

4. OpenID discovery

GET /.well-known/openid-configuration returns the issuer, JWKS URI, and configured scopes:

{
  "issuer": "http://localhost:8000",
  "jwks_uri": "http://localhost:8000/.well-known/jwks.json",
  "scopes_supported": ["name", "email"]
}

The endpoint is public and includes permissive CORS headers.

5. Missing scope response

If a verified token is missing one or more configured fields, the middleware rejects the request with 403 Forbidden:

{
  "error": "missing_scopes",
  "missing": [{ "scope": "email" }]
}

API reference

JWKSAuthMiddleware

Attach it to any Starlette-based MCP server app:

app.add_middleware(
    JWKSAuthMiddleware,
    scopes=[
        {"scope": "name"},
    ],
    verifier=None,
    jwks_path="/.well-known/jwks.json",
    openid_configuration_path="/.well-known/openid-configuration",
    issuer=None,
)

Rules:

  • scopes is required and must contain at least one scope.
  • Every configured scope is mandatory.
  • Scope names must match JWT field names.

get_user() -> AuthUser

Returns the authenticated user's claims for the current request.

user = get_user()
user.email
user["email"]

ScopeDefinition

Optional helper dataclass for typed configuration:

from mcp_auth_middleware import ScopeDefinition

scope = ScopeDefinition(
    scope="email",
)

JWETokenVerifier

Lower-level verifier if you need token verification outside the middleware:

from mcp_auth_middleware import JWETokenVerifier

verifier = JWETokenVerifier()
claims = await verifier.verify_token(token_string)
public_jwks = verifier.get_jwks()

verify_token() returns None when token decryption fails or when the decrypted payload is not a JSON object.

Browser access

/.well-known/openid-configuration already includes CORS headers.

If browser clients also need /.well-known/jwks.json, add CORS middleware after JWKSAuthMiddleware:

from starlette.middleware.cors import CORSMiddleware

app.add_middleware(JWKSAuthMiddleware, scopes=required_scopes)
app.add_middleware(CORSMiddleware, allow_origins=["*"])

Kubernetes deployment

Generate a Secret manifest:

mcp-auth-middleware k8s | kubectl apply -f -

Clean up local key material:

mcp-auth-middleware clean

Mount the generated private key and set:

MCP_KEY_FILE_PATH=/etc/mcp/secrets/key.json

A full example Deployment + Service is in examples/k8s-deployment.yaml.

Environment variables

Variable Required Description
MCP_KEY_FILE_PATH Yes Path to the private JWKS JSON file

License

MIT

About

JWE authentication middleware for http MCP servers. Encrypt user data end-to-end so that only your MCP server can read it.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages