How to Decode a Keycloak JWT: Roles, Scopes, and Token Claims
- Keycloak JWT structure: realm_access and resource_access claims
- How to read realm roles vs client-specific roles
- Preferred_username, email, and other user claims in Keycloak tokens
- Common Keycloak token issues and how decoding helps debug them
Table of Contents
Keycloak JWTs have a distinctive structure — roles are nested inside realm_access and resource_access objects rather than a flat array. Paste your Keycloak token into the decoder above to inspect the full payload. Here is how to interpret what you see.
Decoded Keycloak Access Token — Full Structure
{
"exp": 1700003600,
"iat": 1700000000,
"jti": "abc123-...",
"iss": "https://keycloak.example.com/realms/myrealm",
"aud": ["my-client", "account"],
"sub": "user-uuid-here",
"typ": "Bearer",
"azp": "my-client",
"session_state": "session-uuid",
"scope": "openid email profile",
"sid": "session-uuid",
"email_verified": true,
"name": "Jane Smith",
"preferred_username": "janesmith",
"given_name": "Jane",
"family_name": "Smith",
"email": "[email protected]",
"realm_access": {
"roles": ["default-roles-myrealm", "offline_access", "uma_authorization", "admin"]
},
"resource_access": {
"my-client": {
"roles": ["client-admin", "read-data"]
},
"account": {
"roles": ["manage-account", "view-profile"]
}
}
}
realm_access vs resource_access: The Role Structure
Keycloak separates roles into two categories:
- realm_access.roles: Roles assigned at the realm level. Available across all clients in the realm. Use these for global permissions like "admin" or "superuser".
- resource_access[client-id].roles: Roles assigned to a specific client (application). Each client has its own role namespace. Use these for application-specific permissions.
To check if a user has a realm role in JavaScript:
const payload = decodeJwt(token);
const realmRoles = payload.realm_access?.roles || [];
const hasAdminRole = realmRoles.includes('admin');
// Client-specific role
const clientRoles = payload.resource_access?.['my-client']?.roles || [];
const canReadData = clientRoles.includes('read-data');
Sell Custom Apparel — We Handle Printing & Free Shipping
Debugging Keycloak Token Problems by Decoding
Decoding a Keycloak token helps diagnose these common issues:
- Missing roles: If a user should have a role but it is not in the token, check realm_access AND resource_access. Client roles only appear if the client mapper is configured to include them. In Keycloak admin, go to Client Scopes and verify "roles" mapper is present.
- Wrong issuer: If your API rejects the token, check that
issmatches exactly what your verification library expects — including trailing slash and realm name capitalization. - Audience mismatch: The
audclaim must include your API's client ID. If it is missing, add an "Audience" mapper in the client's mapper configuration. - Token too large: Keycloak tokens grow with each role. If you have hundreds of roles, the token may exceed header size limits (common at 4KB+). Use token optimization or move role-checking server-side.
Reading Username and Email from Keycloak Token
Keycloak uses preferred_username (not just sub) for the human-readable username. The sub is a UUID that does not change even if the username changes.
const payload = decodeJwt(token);
const userId = payload.sub; // permanent UUID
const username = payload.preferred_username; // display username (can change)
const email = payload.email;
const isEmailVerified = payload.email_verified;
const fullName = payload.name;
const issuer = payload.iss;
// Extract realm name from issuer
const realm = issuer.split('/realms/')[1];
For user identity, always use sub as the primary key in your database, not preferred_username — usernames can be changed by admins.
Decode Your Keycloak Token
Paste your Keycloak access token above — see realm_access, resource_access, and all user claims instantly.
Open Free JWT DecoderFrequently Asked Questions
Why do I see "failed to parse jwt keycloak" errors?
This usually means your verification library received a token in the wrong format, the issuer URL has a trailing slash mismatch, or the JWKS endpoint is unreachable. Decode the raw token first to confirm it is structurally valid, then check your issuer URL configuration.
How do I get the Keycloak token in my application?
Use a Keycloak adapter or standard OpenID Connect library. After login, the token is in the keycloak.token property (JavaScript adapter), or returned in the token_endpoint response (standard OAuth2 flow).
Can I decode a Keycloak offline token?
Yes. Offline tokens are JWTs with offline_access scope. Decoding will show the token type and expiry — offline tokens typically have much longer or no expiry, but the refresh token they use is what persists server-side.

