What Is a JWKS in Keycloak?
A complete, no-code walkthrough of the JSON Web Key Set — what it is, how Keycloak builds it, how tokens get verified against it, and how to run it safely in production.
Imagine a nightclub with a bouncer at the door. Every guest carries a wristband stamped with a special seal. The bouncer doesn’t know every guest by face, but he keeps a laminated card behind the counter showing exactly what a “real” seal looks like — the shape, the ink pattern, the hidden watermark. Any wristband that matches the card gets in. Any wristband that doesn’t, however convincing it looks, gets turned away. In the world of Keycloak and modern authentication, that laminated card is the JWKS — the JSON Web Key Set. This post walks through exactly what that card contains, who prints it, how it changes over time, and why almost every secure application quietly depends on it.
1Core Concepts
Before JWKS makes sense, three smaller ideas need to click into place: tokens, keys, and signatures.
What problem are we even solving?
When you log into an application that uses Keycloak, Keycloak doesn’t hand your browser a password receipt. Instead, it hands out a small piece of text called a token — usually a JWT, or JSON Web Token. That token is like a signed note that says “this user is Priya, she logged in at 10:02 AM, and she’s allowed to access the billing service.” Any other service that receives this note needs a way to confirm two things: that the note wasn’t tampered with, and that it really came from Keycloak and not from an impostor.
Think of a JWT like a sealed envelope with a wax stamp from a royal court. Anyone can read the letter inside, but only the royal court has the special stamp ring that presses that exact seal pattern into wax. If you want to check that a letter really came from the court, you don’t need the stamp ring — you just need to know what the court’s official seal is supposed to look like.
Public and private keys, in plain language
Digital signatures rely on a pair of mathematically linked keys. The private key is the “stamp ring” — it can create a signature, and it must never leave Keycloak’s server. The public key is a description of “what a genuine stamp looks like” — it can be given to absolutely anyone, because knowing what a real seal looks like doesn’t let you forge one. Keycloak uses its private key to sign tokens, and it publishes the matching public key so that everyone else can check those signatures.
JWT
JSON Web Token — a compact, signed piece of text that carries claims about a user or a session.
JWK
JSON Web Key — a single cryptographic key described in a standard JSON format, usually a public key.
JWKS
JSON Web Key Set — a JSON document containing a list of JWKs, published at a well-known URL.
Issuer
The authority that created and signed the token — in this case, a specific Keycloak realm.
kid
Key ID — a short label inside both the token header and each JWK, used to match the two together.
Realm
An isolated security domain in Keycloak — its own users, clients, and its own signing keys.
Keycloak rarely has just one signing key. It may keep an old key around during a rotation, or hold separate keys for different algorithms. That’s why the document is a “set” — a small, self-describing catalog of every key currently valid for verifying tokens.
Putting the pieces together
So a JWKS, in one sentence, is a JSON file that Keycloak publishes at a predictable web address, listing the public keys needed to verify every token that realm currently issues. Nothing secret lives in that file. It is meant to be fetched by anyone who needs to trust a Keycloak-issued token — an API gateway, a microservice, a mobile app’s backend, or a third-party partner system.
2Architecture and Components
JWKS doesn’t float in isolation — it sits inside Keycloak’s realm structure and its OpenID Connect discovery machinery.
Where JWKS lives inside Keycloak
Every Keycloak realm has its own key material, its own JWKS endpoint, and its own token issuer identity. This means a company running one Keycloak server with three realms — say, “employees,” “customers,” and “partners” — effectively has three completely separate JWKS documents, three sets of signing keys, and three trust boundaries, even though they live on the same physical server.
The realm as a security island
Because keys are per-realm, a token signed in the “customers” realm can never be verified using the “employees” realm’s JWKS. This isolation is intentional — a breach or key compromise in one realm doesn’t automatically expose the others.
The well-known discovery document
Keycloak follows the OpenID Connect standard, which means every realm exposes a “well-known configuration” document — a kind of map that lists where all the important endpoints live: where to log in, where to exchange a code for a token, where to look up user info, and, importantly, where to fetch the JWKS. Client libraries almost never hardcode the JWKS address; instead, they read it from this discovery document, so if Keycloak ever changes the exact URL structure, well-behaved clients adapt automatically.
Realm Keys
The active signing key(s) generated and stored by Keycloak for a specific realm.
Key Provider
The internal Keycloak module (RSA, ECDSA, or HMAC provider) responsible for generating and managing a key.
Discovery Document
The realm’s OpenID Connect metadata file, pointing to the token, userinfo, and JWKS endpoints.
JWKS Endpoint
The public HTTP endpoint that returns the current list of active public keys as JSON.
Resource Server
Any API or microservice that receives a token and must verify it against the JWKS.
Admin Console
The Keycloak UI where administrators view, generate, or prioritize signing keys per realm.
What actually sits inside a JWK entry
Each key entry in the set carries a handful of fields: a key type (commonly RSA or elliptic curve), an intended use (signing versus encryption), an algorithm name, a unique key ID, and the actual public key material expressed as large numbers encoded in a URL-safe text format. None of this requires memorizing — the important habit is recognizing that this is descriptive metadata, not a mysterious black box.
| Field | Plain-Language Meaning |
|---|---|
| kty | Key type — usually “RSA” or “EC” (elliptic curve) |
| use | What the key is for — “sig” means signing/verifying tokens |
| alg | The signing algorithm, e.g. RS256 or ES256 |
| kid | Key ID — the label used to match a token to its key |
| n, e | For RSA keys: the modulus and exponent that define the public key |
| x5c | Optional certificate chain, if Keycloak includes one |
3Internal Working
How does a key actually get from “generated on the server” to “trusted by a stranger’s API”?
Step one: key generation
When a Keycloak realm starts up for the first time, it automatically generates a signing key pair using a sensible default algorithm (commonly RSA). Administrators can also add additional key providers manually — for example, adding an elliptic-curve key alongside the default RSA one, or importing an existing key from an external certificate authority for compliance reasons.
Generating a key pair is like a locksmith cutting a brand-new master key and, at the same time, photographing the exact shape of that key’s teeth. The photograph (public key) gets pinned to a public noticeboard. The physical key (private key) goes into a safe that only the locksmith touches.
Step two: signing a token
Whenever Keycloak issues a new access token or ID token, it picks the currently “active” key for that realm, computes a cryptographic hash of the token’s contents, and encrypts that hash using the private key. This encrypted hash becomes the token’s signature — the third segment of the classic three-part JWT string. Crucially, Keycloak stamps the token’s header with the kid of the exact key used, so verifiers know precisely which entry in the JWKS to reach for.
Step three: publishing the matching public key
The public half of that same key pair is exposed through the realm’s JWKS endpoint, tagged with the identical kid. This is the linchpin of the whole system: the header says “I was signed with key ABC123,” and the JWKS says “here is exactly what key ABC123’s public half looks like.” Anything else in the JWKS is irrelevant to this particular token.
Step four: verification by a resource server
An API that receives the token reads the kid from its header, looks up that exact entry in the cached JWKS, reconstructs the public key from the JSON fields, and uses it to check whether the signature matches the token’s contents. If the math checks out, the API can trust that the token was genuinely issued by that Keycloak realm and has not been altered in transit — down to a single flipped bit.
Verifying a signature does not tell an API whether a user is still logged in, or whether the token has been revoked. It only proves the token’s contents haven’t been tampered with and that it was genuinely issued by that realm. Expiry and revocation are separate concerns, checked using other claims and mechanisms.
4Data Flow and Lifecycle
Seeing the whole journey end-to-end makes the moving parts click.
sequenceDiagram
participant U as User's Browser
participant KC as Keycloak Realm
participant API as Resource Server (API)
U->>KC: Log in with credentials
KC->>KC: Sign token with private key (kid: ABC123)
KC-->>U: Issue signed JWT
U->>API: Call API with JWT in Authorization header
API->>API: Read "kid" from JWT header
API->>KC: Fetch JWKS (if not already cached)
KC-->>API: Return JSON Web Key Set
API->>API: Match kid, verify signature
API-->>U: Return protected data (if valid)
The lifecycle of a single key
A signing key in Keycloak isn’t permanent. It moves through recognizable stages, and understanding this lifecycle is what separates a system that survives key rotation gracefully from one that suddenly rejects valid users.
Generated
A new key pair is created, either automatically on realm creation or manually by an administrator.
Active
The key is marked as the current signer — every new token from this point uses it, and it appears in the JWKS.
Passive
A newer key becomes active, but the older key stays in the JWKS so tokens it already signed can still be verified.
Disabled
The key is turned off; it can no longer sign new tokens, and any token still bearing its kid will fail verification.
Removed
The key is deleted entirely from the realm and disappears from the JWKS document.
Access tokens are usually short-lived, but ID tokens, refresh tokens, and cached sessions can outlive a rotation. Keeping the old key passive — present in the JWKS but no longer used to sign anything new — is what prevents a rotation from instantly invalidating everyone who is mid-session.
Caching on the verifying side
Resource servers don’t fetch the JWKS on every single request — that would be slow and would hammer Keycloak with traffic. Instead, most Keycloak client libraries cache the JWKS in memory for a configurable period. If a token arrives referencing a kid the cache doesn’t recognize, the library refreshes the JWKS once, on the assumption that a rotation just happened, before giving up.
5Advantages, Disadvantages, and Trade-offs
JWKS-based verification is popular for good reasons, but it isn’t free of trade-offs.
Advantages
- Resource servers verify tokens locally, without calling Keycloak on every request
- Keys can rotate without breaking already-issued, still-valid tokens
- Standardized format means any OpenID Connect-compliant library can consume it
- No shared secret ever needs to be distributed to dozens of microservices
- Multiple algorithms and keys can coexist during migrations
Disadvantages / Trade-offs
- A stale local cache can briefly reject tokens signed with a brand-new key
- Local verification means a resource server can’t instantly know a token was revoked early
- Misconfigured issuer or audience checks can let tokens from the wrong realm slip through
- Clock drift between servers can cause valid tokens to appear expired or “not yet valid”
6Security
JWKS is a security mechanism, so it deserves careful handling on both sides of the fence.
Protecting the private key
The private signing key never appears anywhere in the JWKS — that is the entire point of asymmetric cryptography. In production Keycloak deployments, that private key material is typically stored in an encrypted database, or delegated to a hardware security module or an external vault for organizations with strict compliance requirements. If that private key ever leaks, an attacker could forge tokens that appear perfectly legitimate to every downstream service.
Validating more than just the signature
A signature check alone is not a complete security check. A properly configured resource server also verifies the issuer claim (does this token actually claim to come from the expected realm?), the audience claim (was this token meant for me, specifically?), and the expiry claim (is this token still within its valid time window?). Skipping any of these checks can let a technically well-signed but inappropriate token through.
Signature
Confirms the token wasn’t altered and came from a holder of the matching private key.
Issuer (iss)
Confirms the token claims to originate from the exact realm URL you expect.
Audience (aud)
Confirms the token was intended for your specific API or client, not a different one.
Expiry (exp)
Confirms the token hasn’t outlived its stated lifetime.
Transport security for the JWKS endpoint itself
Because the JWKS is fetched over HTTP(S), it must be retrieved over a trusted, encrypted connection. If an attacker could intercept and swap the JWKS response in transit, they could substitute their own public key and trick a resource server into trusting forged tokens. This is why the JWKS endpoint should always sit behind TLS, and why resource servers should validate the certificate of the Keycloak host they’re talking to.
Hardcoding a JWKS response as a static file “for performance” defeats the entire purpose of rotation and revocation. If keys ever change, every service using the stale copy will silently keep trusting an outdated — or worse, compromised — key.
7Monitoring, Logging, and Metrics
Because JWKS problems often show up as a wave of failed logins, watching the right signals early prevents a lot of confusion.
Signals worth tracking
Teams operating Keycloak at scale typically watch for a sudden spike in token-verification failures right after a deployment or a key rotation, unusually high JWKS endpoint traffic (a sign that caching isn’t working as intended somewhere), and warnings in Keycloak’s own logs about key generation, rotation, or provider errors.
Correlating failures with rotation events
A useful operational habit is logging the kid of every rejected token. If failures cluster around one specific, recently-retired kid, that’s a strong signal that some client or service is caching an old JWKS far longer than it should.
Watching clock synchronization
Because expiry checks rely on comparing timestamps, servers with drifting system clocks can start rejecting tokens that are, in reality, perfectly valid. Monitoring NTP synchronization health across the fleet is a quiet but important safeguard.
8Design Patterns and Anti-patterns
Some habits make JWKS-based systems resilient; others quietly set up future outages.
Problem
A team copies the JWKS JSON once during setup and bakes it into application configuration as a static file, believing it “never changes.”
Why It’s Harmful
The moment Keycloak rotates its signing key — whether planned or in response to a suspected compromise — every service using the frozen copy starts rejecting all new tokens, causing a full authentication outage.
Correct Approach
Always fetch the JWKS dynamically at runtime through a library that supports caching with a refresh strategy, so rotations are absorbed automatically.
Problem
A resource server verifies the token’s signature but skips checking the issuer and audience claims, assuming “if it’s signed, it must be fine.”
Why It’s Harmful
A perfectly valid token issued for a completely different application, or a different realm, could still pass signature verification and be misused against an API it was never meant for.
Correct Approach
Always validate issuer, audience, and expiry alongside the signature — signature validity is necessary, but not sufficient, for trust.
A healthier pattern: overlap-based rotation
The recommended pattern is to always keep at least one previous key “passive” in the JWKS for a window slightly longer than your longest-lived token’s lifetime. This overlap guarantees that no legitimately issued token ever becomes unverifiable purely because of a rotation timing coincidence.
9Best Practices and Common Mistakes
A short, practical checklist for teams operating Keycloak in production.
Use standard libraries
Let a well-maintained OpenID Connect library handle JWKS fetching, caching, and refresh logic instead of writing it by hand.
Rotate on a schedule
Rotate signing keys periodically, not only reactively after an incident, so rotation itself stays a routine, well-tested event.
Set sensible cache TTLs
Balance freshness against load — long enough to avoid hammering the endpoint, short enough to pick up rotations quickly.
Alert on kid mismatches
Treat a wave of unrecognized key IDs as an early warning sign, not just a routine error to swallow silently.
Forgetting that each Keycloak realm has its own JWKS. Pointing a resource server at the wrong realm’s JWKS endpoint will cause every token to fail verification, even though nothing is “wrong” with either realm individually.
10Real-World and Industry Examples
JWKS isn’t a Keycloak-only invention — it’s a shared industry standard that Keycloak implements faithfully.
Enterprise single sign-on
Large organizations running Keycloak as their central identity provider expose one JWKS per business unit’s realm, letting dozens of internal applications trust the same identity platform without ever sharing a secret key between teams.
API gateways
Many API gateway products can be configured to fetch a Keycloak realm’s JWKS directly and enforce token verification at the network edge, before a request ever reaches application code.
Cross-industry adoption of the same standard
Identity platforms such as Auth0, Okta, Azure AD, and Google’s identity services all publish JWKS documents in the same standardized shape. A developer who understands Keycloak’s JWKS already understands most of what these other platforms do too.
11Frequently Asked Questions
No. It only contains public keys, which are meant to be shared openly. It should still be served over HTTPS to prevent tampering in transit, but there is nothing confidential inside the JSON itself.
As long as the old key remains listed in the JWKS as “passive,” tokens signed with it can still be verified until they naturally expire. Only removing the key entirely breaks those tokens.
No. Each realm maintains its own independent set of signing keys and its own JWKS endpoint, even on a single shared Keycloak server.
Yes. It’s common to see both RSA and elliptic-curve entries in the same set, especially during a migration from one algorithm to another.
There’s no universal number, but many organizations rotate on a schedule measured in months, treating rotation as routine maintenance rather than an emergency response tool.
No. JWKS protects the integrity of tokens through signatures, but transport-level encryption via HTTPS is still essential to prevent eavesdropping and tampering with the traffic carrying both tokens and the JWKS itself.
12Summary and Key Takeaways
A JWKS is Keycloak’s public, ever-updating catalog of the keys needed to verify its signed tokens. It lets any API, gateway, or service trust Keycloak-issued tokens without ever needing a shared secret, while still allowing keys to rotate safely behind the scenes. Understanding the lifecycle of a key — generated, active, passive, disabled, removed — and validating more than just the signature are what separate a fragile integration from a resilient one.
Key Takeaways
- JWKS is public by design — it contains only public keys, never private ones.
- Each realm is isolated — its own keys, its own JWKS endpoint, its own trust boundary.
- The “kid” is the glue — it links a token’s header to the exact key that must verify it.
- Rotation needs overlap — old keys should stay passive long enough for existing tokens to expire naturally.
- Signature checks aren’t enough alone — issuer, audience, and expiry must be validated too.
- Caching is essential but must expire — a frozen JWKS copy quietly guarantees a future outage.
- The standard is bigger than Keycloak — the same JWKS shape is used across most modern identity platforms.