How It Works
AuthPlane is a standalone OAuth 2.1 authorization server purpose-built for the Model Context Protocol (Authorization spec 2025-11-25). It sits between MCP clients and your MCP server, handling the entire authorization dance so your server only needs to verify JWTs.
Architecture
Section titled “Architecture”Key design principle: AuthPlane handles the OAuth complexity. Your MCP server verifies JWTs against a cached JWKS — once the keys are fetched, token validation happens locally.
The authorization flow
Section titled “The authorization flow”Step 1: Discovery
Section titled “Step 1: Discovery”When an MCP client connects to your server and gets a 401, it discovers which authorization server to use via RFC 9728 Protected Resource Metadata — a document the AuthPlane SDK serves from your MCP server:
GET /.well-known/oauth-protected-resource/mcp HTTP/1.1Host: mcp.yourcompany.com
200 OK{ "resource": "https://mcp.yourcompany.com/mcp", "authorization_servers": ["https://auth.yourcompany.com"]}The client then fetches the AS metadata (RFC 8414) to discover all endpoints:
GET /.well-known/oauth-authorization-server HTTP/1.1Host: auth.yourcompany.com
200 OK{ "issuer": "https://auth.yourcompany.com", "authorization_endpoint": "https://auth.yourcompany.com/oauth/authorize", "token_endpoint": "https://auth.yourcompany.com/oauth/token", "registration_endpoint": "https://auth.yourcompany.com/oauth/register", ...}Step 2: Client identification (CIMD or DCR)
Section titled “Step 2: Client identification (CIMD or DCR)”Modern MCP clients identify themselves with a Client ID Metadata Document (CIMD, IETF draft) — a JSON document hosted at a URL the client controls. The client_id is the URL; AuthPlane fetches and validates the metadata (HTTPS required by default, SSRF-guarded):
{ "client_id": "https://client.example.com/.well-known/oauth-client.json", "client_name": "Example MCP Client", "redirect_uris": ["http://localhost:9876/callback"], "grant_types": ["authorization_code"], "response_types": ["code"]}Step 3: Authorization + PKCE
Section titled “Step 3: Authorization + PKCE”The client generates a PKCE verifier/challenge pair (S256 — plain is rejected) and sends the user to the consent screen, binding the request to your MCP server with the RFC 8707 resource parameter:
GET /oauth/authorize ?response_type=code &client_id=https://client.example.com/.well-known/oauth-client.json &redirect_uri=http://localhost:9876/callback &scope=mcp:echo mcp:search &resource=https://mcp.yourcompany.com/mcp &code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM &code_challenge_method=S256 &state=xyz123The user sees a consent screen listing the requested scopes. If an upstream IdP is configured, the user authenticates there first via SSO.
Step 4: Token issuance
Section titled “Step 4: Token issuance”After consent, the client exchanges the authorization code for tokens:
POST /oauth/token HTTP/1.1Host: auth.yourcompany.comContent-Type: application/x-www-form-urlencoded
grant_type=authorization_code&code=auth_code_here&redirect_uri=http://localhost:9876/callback&client_id=https://client.example.com/.well-known/oauth-client.json&code_verifier=dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXkAuthPlane returns an RFC 9068 JWT access token (typ: at+jwt, with iss, sub, aud, exp, jti, client_id, scope claims — aud set from the resource parameter) plus a refresh token. Refresh tokens rotate on every use; reuse of a consumed token revokes the whole family. With DPoP enabled, tokens are additionally bound to a client-held key via the cnf.jkt claim.
Step 5: JWT verification in your MCP server
Section titled “Step 5: JWT verification in your MCP server”Your MCP server validates tokens with an AuthPlane SDK — discovery, JWKS caching, audience binding, and scope enforcement in a few lines:
auth = await authplane_auth( issuer=os.environ["AUTHPLANE_ISSUER"], base_url=os.environ["AUTHPLANE_BASE_URL"], scopes=["mcp:echo"],)mcp = FastMCP("demo-server", **auth)import { authplaneMcpAuth } from "@authplane/mcp";
const auth = await authplaneMcpAuth({ issuer: process.env.AUTHPLANE_ISSUER!, resource: process.env.AUTHPLANE_RESOURCE!, scopes: ["mcp:echo"],});app.get(auth.protectedResourceMetadataPath, auth.protectedResourceMetadataHandler);app.use("/mcp", auth.bearerAuth);adapter := must(authplanemcp.NewAdapter(ctx, authplanemcp.Options{ Issuer: os.Getenv("AUTHPLANE_ISSUER"), Resource: os.Getenv("AUTHPLANE_RESOURCE"), Scopes: []string{"mcp:echo"},}))http.Handle(adapter.WellKnownPRMPath(), adapter.ProtectedResourceMetadataHandler())http.Handle("/mcp", adapter.AuthMiddleware(handler))See the full integration guides: Python, TypeScript, Go.
Data flow
Section titled “Data flow”| What | Where | Who controls it |
|---|---|---|
| User credentials | Your IdP (Okta, Entra, Google, Auth0) | You |
| OAuth tokens & audit log | AuthPlane database (PostgreSQL/SQLite) | You |
| Vaulted upstream tokens | AuthPlane database, encrypted at rest | You |
| JWKS public keys | AuthPlane /.well-known/jwks.json | You |
| MCP server data | Your database | You |
AuthPlane runs in your infrastructure. No data leaves your perimeter, and the server sends no telemetry home.
Upstream IdP federation
Section titled “Upstream IdP federation”AuthPlane can delegate user authentication to your existing identity provider — Google, Okta, Microsoft Entra ID, Auth0, or any OIDC-compliant provider. Enable it with AUTHPLANE_OIDC_ENABLED=true and configure providers in YAML; unauthenticated users are redirected to your IdP for SSO, then return to AuthPlane to approve the MCP client’s scope request.
For enterprise-managed authorization where the IdP mediates every agent-to-tool connection (XAA / ID-JAG via RFC 7523 JWT Bearer), see the federation guides.
Deployment topology
Section titled “Deployment topology”# Development — SQLite, auto-generated keys, zero configdocker run -p 9000:9000 -p 9001:9001 \ -e AUTHPLANE_ADMIN_API_KEY -e AUTHPLANE_SESSION_SECRET \ -v authserver-data:/data \ authplane/authserver:latest serveProduction runs the same binary against PostgreSQL, with multiple instances behind a load balancer sharing one database (cache invalidation via LISTEN/NOTIFY). JWT verification is stateless, so your MCP servers keep working even if AuthPlane is briefly down.
Continue with the Docker guide, the Kubernetes guide, and the topology catalog.