What is JWKS, and why your MCP server needs it
JWKS MCP server validation explained: how the public key set from an OIDC identity provider validates enterprise JWTs without per-request IdP calls.
Written by
Mack Chi
JWKS MCP server validation, in one sentence
A JWKS MCP server validates incoming JWTs locally against the public key set its identity provider already publishes — no per-request introspection call, no shared secret, no new integration. JWKS (JSON Web Key Set, RFC 7517) is the same pattern Okta, Auth0, and Entra customers already use for every other OIDC-protected app. For MCP, it is the right answer for the same reasons: low latency, automatic key rotation, and zero new auth surface area.
This note is short on purpose: one paragraph of definition, one JSON example, one ten-line validation snippet, and the opinion. The full enterprise walkthrough — multiple IdPs, key rotation, gateway propagation, the security checklist — lives in Building Enterprise-Ready MCP Servers with JWKS and Identity Providers. Use this page as the link to drop in a Slack thread when a coworker asks "what is JWKS?" and reach for the deep dive when actually shipping a JWKS MCP server to production.
The five-year-old version
Picture a company stamp. The security team owns the only stamper and uses it to stamp permission slips for every employee. The team also pins a giant poster on the wall that shows the stamp in full detail — every curve, every dot. Anyone in the building can walk up to the poster, look at a permission slip, and confirm "yes, that is a real stamp." No phone call to security. No shared key. Just visual comparison.
JWKS is the poster.
More precisely: JWKS (JSON Web Key Set, RFC 7517) is the set of public keys an identity provider publishes at a well-known URL so any service can verify the signatures on JWTs the IdP issued, without ever contacting the IdP itself. The IdP holds the private key. The IdP signs JWTs with it. The IdP publishes the matching public keys at something like
https://your-idp.com/.well-known/jwks.json. A JWKS MCP server downloads those keys once, caches them, and validates incoming JWTs locally. No round-trip to the IdP per request. No shared secret to leak. Just math.What the document actually looks like
A
curl against an IdP's JWKS URL returns something like this:{
"keys": [
{
"kty": "RSA",
"kid": "key-2026-05",
"use": "sig",
"alg": "RS256",
"n": "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx...",
"e": "AQAB"
}
]
}
The only field most code cares about day-to-day is
kid — the key ID. Every JWT the IdP issues carries a kid in its header that says "this token was signed with this specific key." The server looks the kid up in the JWKS, grabs the matching public key, and verifies the signature with it. When the IdP rotates keys (which it should, on a schedule), the new key shows up in the JWKS automatically. No redeploy. No config file update. Rotation just works.The validation snippet
Here is the entire token-validation path in Node, using
jose:import * as jose from 'jose';
const JWKS = jose.createRemoteJWKSet(new URL('https://your-idp.com/.well-known/jwks.json'));
export async function verifyMcpToken(token: string) {
const { payload } = await jose.jwtVerify(token, JWKS, {
issuer: 'https://your-idp.com/',
audience: 'https://your-mcp-server.example.com',
clockTolerance: 30,
});
return payload; // sub, email, roles, org_id, whatever the IdP includes
}
Ten lines, give or take.
createRemoteJWKSet handles the network fetch, the cache, and the unknown-kid refresh. jwtVerify checks the signature, the iss, the aud, the exp, and returns the claims. That is the entire validation layer of an enterprise JWKS MCP server. Python is the same shape with pyjwt + PyJWKClient — same idea, same five claims to check.Every Bearer token the MCP server receives runs through that function before any tool handler sees it. If it returns, the request has a verified user identity and authorization can run on the claims (roles, group membership, org id). If it throws, the server returns a
401 with a WWW-Authenticate header pointing at its resource metadata, and a standards-compliant MCP client will discover the IdP and start the OAuth flow without anyone touching a config file. That part of the dance is covered in the MCP OAuth 2.1 quick reference.The opinion
Every enterprise JWKS MCP server should validate tokens via JWKS by default. That is the whole take.
A few notes on why:
- The alternative is calling the IdP on every request. Okta, Auth0, and Entra all expose token introspection endpoints. They work. They also add 50-300ms of network latency to every single tool call, and they turn the IdP into a hard dependency for every MCP request. For a chatty agent making fifteen tool calls per turn, that is a multi-second tax on every conversation. JWKS validation runs in microseconds against a cached public key. There is no contest.
- The other alternative is terminating auth at a gateway and calling upstream servers with separate credentials. That is a fine pattern — it is the default for most enterprise deployments — but it means an MCP server cannot enforce its own access control based on the original user's claims. The gateway sees the user. The upstream server sees a service account. JWKS validation at both layers (gateway and upstream server) delivers end-to-end identity: the gateway validates, the gateway propagates the original JWT, and the upstream server independently validates it again and reads the claims. Same
jose.jwtVerifycall. Same JWKS endpoint. Zero extra integration glue. - And the worst alternative is rolling custom auth. Every "just use a shared API key in an environment variable" setup eventually becomes "eight services with eight different rotation policies and one of them is from 2023." JWKS is what the rest of the stack already does. Use it for MCP too.
The only real reason not to validate via JWKS is the absence of an OIDC-capable IdP — at which point MCP authentication is no longer the biggest problem on the board.
Where to go next
- The long-form walkthrough: Building Enterprise-Ready MCP Servers with JWKS and Identity Providers — covers caching, key rotation, the security checklist, the
WWW-Authenticate401, and per-IdP configuration for Okta, Auth0, and Entra. - The OAuth side of the same picture: MCP OAuth 2.1 quick reference — the five endpoints, PKCE, and the
audclaim everyone forgets. - A working example: mcp-server-jwks-keycloak — runnable with one
docker compose up, includes role-based tool access and an end-to-end test.
If "MCP authentication" sounds like a big project, the new part is small. JWKS is the part that is already on the wall.
