What Is a JWT in Keycloak?
After a successful login, Keycloak hands your application a strange-looking block of text starting with "eyJ…". That block is a JWT — and understanding what's actually inside it demystifies a huge part of how modern authentication works.
Imagine a concert wristband that isn’t just a plain plastic strip, but one printed with your name, which section you’re allowed into, what time your ticket expires, and a tamper-proof holographic seal that instantly reveals if anyone tried to alter it. A security guard glancing at your wrist doesn’t need to call the box office to double-check — everything they need to know, and proof that it hasn’t been faked, is right there on the band itself. A JWT (JSON Web Token) issued by Keycloak works exactly like this: a self-contained, tamper-evident piece of information proving who you are and what you’re allowed to do, without the application needing to call Keycloak back every single time to check.
1What Is a JWT?
The foundation everything else in this guide builds on.
A JWT, pronounced “jot,” stands for JSON Web Token — a compact, text-based format for securely representing a set of claims about a user or system. When you log in through Keycloak, it doesn’t just say “yes, login successful” — it hands your application one or more JWTs packed with useful, verifiable information: who you are, what roles you hold, and how long this proof remains valid.
Think of a JWT like a sealed, printed boarding pass rather than a simple verbal promise. The airline doesn’t need to phone you back to confirm your seat every time you walk past a gate agent — the boarding pass itself carries your name, flight number, and seat, printed under a barcode that proves it was genuinely issued by the airline and hasn’t been tampered with.
The key property that makes JWTs so useful is that they’re self-contained and verifiable. An application receiving a JWT can check that it’s genuine and read the information inside it without needing to make a separate phone call back to Keycloak for every single request.
Self-Contained
All the necessary information travels inside the token itself, rather than being looked up elsewhere.
Digitally Signed
A cryptographic signature proves the token genuinely came from Keycloak and hasn’t been altered.
Compact and Text-Based
Encoded as a single line of URL-safe text, easy to pass around in web requests.
Readable Without Secrets
Its contents can be decoded and read by anyone who has the token — signing prevents tampering, but it doesn’t hide the contents.
“Signed” does not mean “secret.” Anyone holding a JWT can read everything inside it — the signature only proves it hasn’t been tampered with. This distinction matters enormously and is explored further in Chapter 8.
2JWT vs. Session Cookie vs. Opaque Token
Keycloak can issue different kinds of proof-of-login — knowing the difference clarifies why JWTs are so popular.
A session cookie is like being handed a plain numbered ticket stub — the ticket itself is meaningless until the venue looks up that number in their own records to see who it belongs to. A JWT is like the printed boarding pass from Chapter 1 — self-describing and independently checkable. An opaque token sits in between: a random-looking string that, like the ticket stub, also requires calling back to the issuer to find out what it actually means.
| Token Type | Contents Readable Directly? | Requires a Lookup to Validate? |
|---|---|---|
| JWT | Yes — decode and read directly | No — signature can be checked independently |
| Session Cookie | No — just an ID referencing server-side data | Yes — server must look up the session |
| Opaque Token | No — meaningless without the issuer | Yes — issuer must be asked what it represents |
Because a JWT can be verified independently, an application (or several separate microservices) can check whether a user is legitimately logged in without repeatedly calling Keycloak — a major reason JWTs are so widely used in modern, distributed systems.
3The Anatomy of a JWT: Three Parts
Every JWT, no matter which system issues it, is built from exactly three sections joined together.
A JWT is made of three separate sections, encoded as text and joined by periods: a header, a payload, and a signature. Each part serves a distinct purpose, and understanding them individually removes almost all the mystery around that strange “eyJ…” string.
Header
Describes the token type and which signing algorithm was used to protect it.
Payload
Contains the actual claims — the meaningful information about the user, their roles, and the token’s validity window.
Signature
A cryptographic value proving the header and payload haven’t been altered since Keycloak issued the token.
flowchart LR
A[Header
algorithm + token type] --> D[Joined with periods]
B[Payload
claims about the user] --> D
C[Signature
proves authenticity] --> D
D --> E[Final JWT String]
Think of a certified letter. The header is like the envelope’s markings saying “this is a certified letter, sealed with wax.” The payload is the actual letter content inside. The signature is the wax seal itself — anyone can read the letter once it’s opened, but the intact seal is what proves it wasn’t tampered with in transit.
The header and payload are only encoded for safe transport, not encrypted — they can be decoded and read by anyone with the token. Only the signature requires Keycloak’s private signing key to produce.
4How Keycloak Issues and Signs a JWT
Walking through what happens the moment a login succeeds.
The User Successfully Authenticates
Credentials are verified against the realm’s user directory, as covered in earlier guides on Keycloak realms and login flows.
Keycloak Assembles the Claims
User details, assigned roles, token validity window, and other information are gathered into the payload.
Keycloak Signs the Token With Its Private Key
Using a signing key specific to that realm, Keycloak produces a signature over the header and payload together.
The Complete JWT Is Returned to the Application
The finished token — header, payload, and signature joined together — is handed back as part of the login response.
sequenceDiagram
participant U as User
participant K as Keycloak
participant App as Application
U->>K: Log in successfully
K->>K: Build claims (identity, roles, expiry)
K->>K: Sign token using realm's private key
K-->>App: Return signed JWT
App->>App: Store and later use the JWT
Each realm in Keycloak has its own signing key, which means a token issued by one realm is cryptographically meaningless to an application checking against a different realm’s key — reinforcing the strict realm isolation covered in earlier guides.
5Common Claims Inside a Keycloak JWT
A closer look at the specific pieces of information typically found in the payload.
sub (Subject)
A unique, stable identifier for the user the token represents.
iss (Issuer)
Identifies exactly which Keycloak realm issued this token.
aud (Audience)
Specifies which application or service the token is intended for.
exp (Expiration)
The exact moment this token stops being valid, after which it must be refreshed or reissued.
iat (Issued At)
Records the exact time the token was originally created.
realm_access
A Keycloak-specific claim listing the realm-level roles assigned to this user.
resource_access
A Keycloak-specific claim listing roles assigned per individual client application.
preferred_username
A human-friendly username, often shown directly in an application’s interface.
These claims are like the different printed fields on that concert wristband — the wearer’s name, which sections they can enter, when the band expires, and which venue issued it. Anyone can glance at the wristband and read all of this without needing to ask the box office.
Realm roles (realm_access) apply broadly across the whole realm, while client roles (resource_access) are scoped to one specific application — an important distinction when deciding what a particular permission should actually control.
6The Lifecycle of a JWT
A token’s life doesn’t end the moment it’s issued — it goes through several stages.
flowchart LR
A[Token Issued at Login] --> B[Used on Each API Request]
B --> C{Still Within Expiry?}
C -->|Yes| B
C -->|Expired| D[Refresh Token Used to Get New JWT]
D --> B
C -->|Refresh Token Also Expired| E[User Must Log In Again]
Keycloak typically issues both a short-lived access token (itself a JWT) and a longer-lived refresh token. When the access token’s expiry time passes, the application uses the refresh token to silently request a brand-new JWT — without forcing the user to type their credentials again — right up until the refresh token itself eventually expires.
Because a JWT is self-contained and cannot be individually “called back” once issued, keeping its lifespan short is one of the main ways Keycloak limits how long a stolen or leaked token could remain useful.
7How Applications Validate a JWT
What a resource server actually checks before trusting a token handed to it.
When an application receives a JWT, it doesn’t simply trust the claims inside at face value — it runs through a specific validation checklist before treating the request as legitimate.
Verify the Signature
Using Keycloak’s public key, the application confirms the token’s header and payload weren’t altered after signing.
Check the Issuer
The application confirms the “iss” claim matches the expected Keycloak realm, rejecting tokens from unexpected sources.
Check the Audience
The application confirms the “aud” claim indicates the token was actually intended for this specific service.
Check the Expiry
The application rejects any token whose “exp” timestamp has already passed.
To verify the signature, applications fetch Keycloak’s public signing keys from a well-known endpoint, often referred to by the acronym JWKS (JSON Web Key Set). Because this uses public-key cryptography, applications can verify a signature without ever needing Keycloak’s actual private signing key.
It’s similar to verifying a banknote’s watermark against light — you don’t need the mint’s actual printing plates to check authenticity, just a publicly known way to verify the mark was made by the real mint.
8Security Considerations Around JWTs
The specific risks that come from a token being self-contained and independently readable.
Contents Are Not Secret
Anyone holding a JWT can decode and read its full payload — sensitive personal data should never be placed inside it.
No Built-In Instant Revocation
Because a JWT is self-contained, it typically stays valid until it naturally expires, even if the underlying account is disabled in the meantime.
Theft Equals Full Impersonation
Anyone who obtains a valid, unexpired JWT can use it exactly as the legitimate holder could, until it expires.
Insecure Storage on the Client
Where and how an application stores a JWT after receiving it significantly affects how exposed it is to theft.
Since JWTs typically can’t be individually revoked the way a server-tracked session can, keeping their lifespan short is the primary way Keycloak limits the damage a stolen token could cause before it naturally stops working.
9Design Patterns and Anti-Patterns
Lessons learned from teams who’ve handled JWTs incorrectly in production.
Problem
Placing sensitive personal information — such as private contact details or confidential internal data — directly inside a JWT’s payload.
Why It’s Harmful
Because the payload is only encoded, not encrypted, anyone who intercepts or is handed the token can read that sensitive data directly, without needing to break any cryptography at all.
Correct Approach
Keep JWT payloads limited to identity and permission claims genuinely needed for access decisions, and fetch any sensitive personal data separately through an authenticated, authorized request instead.
Problem
Storing JWTs in browser storage that’s easily reachable by malicious scripts running on the same page.
Why It’s Harmful
If an attacker manages to run unauthorized code on a page, that storage location becomes an easy target, potentially exposing the token and allowing full impersonation of the logged-in user.
Correct Approach
Favor storage mechanisms designed to resist casual script access, and always pair this with short token lifespans so that even a stolen token has a narrow window of usefulness.
Design Pattern: Short-Lived Access JWT, Long-Lived Refresh Token
Pairing a short-lived JWT for everyday API calls with a separate, more carefully guarded refresh token balances convenience against the self-contained, hard-to-revoke nature of JWTs.
10Best Practices and Common Mistakes
Practical guidance for anyone working with Keycloak-issued JWTs.
Always Verify the Signature Before Trusting a Token
Never read claims out of a JWT and act on them without first confirming the signature is valid.
Check Issuer, Audience, and Expiry Every Time
A valid signature alone isn’t sufficient — confirm the token was actually meant for this realm, this application, and is still within its valid window.
Keep Token Lifespans Reasonably Short
Balance user convenience against the risk of a stolen token remaining useful for too long.
Never Put Secrets Inside the Payload
Treat everything inside a JWT’s payload as readable by anyone who ever holds the token.
Common missteps include skipping audience validation (accepting a token meant for a different application), assuming a JWT’s contents are private just because it “looks encrypted,” and forgetting that disabling a user account doesn’t instantly invalidate JWTs already issued to them before expiry.
11Advantages and Disadvantages of JWTs
A fair comparison against traditional server-tracked sessions.
Advantages
- Applications can verify a token independently, without calling Keycloak on every request
- Works naturally across multiple separate services and microservices
- Compact and easy to pass around in standard web requests
- Carries useful, structured claims like roles directly inside the token
Disadvantages / Trade-offs
- Cannot typically be instantly revoked before their natural expiry
- Contents are readable by anyone holding the token, unlike an opaque reference
- Larger in size than a simple session ID, adding a little overhead to every request
- Requires careful, consistent validation logic in every service that accepts them
For systems built from many independent services — a very common modern architecture — the ability to verify a token locally, without a round trip back to Keycloak for every request, is a major performance and scalability advantage that outweighs the trade-offs for most use cases.
12Monitoring and Auditing JWT Usage
Even though JWTs are self-contained, meaningful oversight is still possible and important.
Token Issuance Logging
Recording when and to whom Keycloak issues tokens provides a clear trail of authentication activity across a realm.
Signature Validation Failure Tracking
Repeated signature or issuer validation failures at a resource server can signal tampered, expired, or forged tokens being attempted.
Refresh Token Usage Auditing
Because refresh tokens are longer-lived and more sensitive, tracking their use helps spot unusual patterns that might indicate compromise.
13Real-World and Industry Examples
Seeing Keycloak-issued JWTs at work in common architectures.
Microservices Authentication
A system broken into many small, independent services can each verify an incoming JWT locally using Keycloak’s public key, avoiding the need for every service to call back to a central authentication server on every request.
API Gateways
A gateway sitting in front of many backend services often validates a JWT once at the edge, then passes the already-verified claims along, letting downstream services trust the gateway’s check.
Mobile Application Backends
Mobile apps commonly store a Keycloak-issued JWT after login and attach it to every API call, letting the backend confirm identity and roles without maintaining server-side session state for every mobile user.
Single Page Web Applications
A browser-based app can read claims like the username or granted roles directly out of its own JWT to adjust what’s shown on screen, while still relying on the backend to independently re-validate the token for actual data access.
14Frequently Asked Questions
Not by default. A standard JWT is encoded for safe transport and signed for tamper protection, but its contents can be decoded and read by anyone holding the token — it should never be treated as a secure place to hide sensitive data.
Because a JWT is self-contained and verified independently rather than looked up on a server, it generally remains technically valid until its own expiry time passes, even if the underlying account is disabled in the meantime — which is why keeping token lifespans short matters.
realm_access lists roles that apply broadly across the entire realm, while resource_access lists roles scoped specifically to one individual client application.
The application checks the token’s signature against Keycloak’s public signing key for that realm, typically retrieved from a well-known key endpoint — a mismatch means the token was altered or wasn’t genuinely issued by that realm.
Typically, access tokens and ID tokens issued by Keycloak are JWTs, while refresh tokens may or may not be, depending on configuration — the important part is understanding what each token type is used for rather than assuming every token behaves identically.
Any change to the header or payload invalidates the original signature, so a properly validating application will immediately reject the altered token as tampered — this is precisely the protection the signature exists to provide.
15Summary and Key Takeaways
A JWT is Keycloak’s way of packaging proof of a successful login into a compact, self-contained, digitally signed piece of text — carrying identity and permission information that any application can independently verify without calling back to Keycloak for every request. Understanding its three parts, its common claims, and how signature validation works turns that intimidating “eyJ…” string into a clearly understandable piece of the authentication puzzle.
Key Takeaways
- A JWT is self-contained and independently verifiable — applications can check it without calling Keycloak back on every request.
- Every JWT has three parts: a header, a payload of claims, and a signature proving authenticity.
- Signed does not mean secret — the payload is readable by anyone holding the token, so sensitive data should never be placed inside it.
- Common claims like sub, iss, aud, and exp carry identity, source, intended recipient, and expiry information.
- realm_access and resource_access are Keycloak-specific claims separating realm-wide roles from client-specific ones.
- Applications must verify signature, issuer, audience, and expiry before trusting any claim inside a JWT.
- Short expiry windows are the primary defense against a JWT’s lack of built-in instant revocation.