Keycloak and Enterprise Identity
A Realm Is an Isolation Boundary
Summary
A realm is a fully isolated unit that holds users, clients, roles, and keys. If the realms differ, they do not know each other's users.
Why this was needed
When you first open Keycloak, there is a master realm. Creating application users here is the first mistake. master is the realm that manages Keycloak itself, and the users here are entangled with Keycloak administration permissions. You must create a separate realm for your application.
What it means for a realm to be an isolation unit is concrete. Each realm has different signing keys, a different user store, and a different token issuer (iss). So a token from realm A fails verification at realm B's API. The design of giving each tenant its own realm in a multi-tenant SaaS comes from here — however, when the number of realms reaches hundreds, management and memory burden grow, so usually tenants are distinguished by groups and attributes within a single realm.
How it works
A client is an application that can request tokens within a realm. They divide into two kinds.
A public client has no secret. SPAs and mobile apps belong here, and PKCE must be turned on. It is also important to register the redirect URI precisely — using wildcards broadly becomes a route for token theft.
A confidential client has a secret. Backend servers belong here, and if you turn on the service account, it can obtain its own token through the client credentials flow.
Roles come in two levels. A realm role is meaningful across the whole realm (for example, admin), and a client role is meaningful only within a specific client (for example, the orders-api client's refund). When there are several services, separating them by client roles prevents name collisions.
A group is a collection of users and can have roles mapped to it. Instead of giving roles individually to 300 users, you give the role to a group and put the users in the group. Groups can have a hierarchy, and a subgroup inherits the roles of its parent.
A composite role is a role that contains other roles. If you make order-admin contain order-reader, you do not need to give an administrator the two roles separately.
What you meet in the field
It is easy to get confused about where roles go in the token. Realm roles go in realm_access.roles, and client roles go in resource_access.<클라이언트ID>.roles (the client ID). And if you turn off a client's "full scope allowed", roles not mapped to that client are dropped from the token. It is used to reduce token size and keep least privilege, but if you turn it off without knowing this, it becomes "I gave the role but it doesn't show in the token".
It is good to script administration tasks with kcadm.sh. Settings made by hand in the web console are not reproducible, and staging and production quietly diverge.
What to look at on the side that verifies the token
However well you configure issuance, it is meaningless if the receiving side does not verify properly. What an API server must check when it receives a token is settled.
- Signature — verify with the realm's public key. Get the key from the JWKS address that
/.well-known/openid-configurationpoints to and cache it, and if an unknown key ID arrives, fetch it again. Keys are rotated, so if you fetch once and use it forever, everything fails on the day of rotation. - Issuer (
iss) — whether it was issued by our realm. If you do not check this, a token issued by another realm or another Keycloak also passes. - Audience (
aud) — whether this token is directed at us. If absent, a token issued for another service is used as is on our API. - Expiry (
exp) — allow only a few tens of seconds of clock skew. The more generous you are, the longer the lifetime of a stolen token.
What you must never do here is choose the algorithm as the token tells you to. If the verifying side trusts the header's alg as is, an attacker can change it to none or a symmetric algorithm and bypass the signature. You must hard-code the expected algorithm in the code and reject immediately anything different.
Decide the token lifetime design together too. The reason to keep access tokens short (a few minutes) and refresh tokens long is that access tokens cannot be revoked. If the signature is valid and it is before expiry, the token keeps working even if you delete the user in Keycloak. So when immediate blocking is needed, you must lean on the short lifetime, or switch to checking the token state on every request, and with the latter every request goes through Keycloak, so you must consider performance and availability together. The answer to the question "I logged out, so why does it still work?" is mostly in this passage.
Finally, you must also decide how to return a verification failure. A wrong signature or issuer is a 401, and if the token is valid but the action is not allowed with that role, it is a 403. If you lump the two together, the client cannot distinguish a situation where it must log in again from one where it must obtain permission, and you get a screen that attempts to log in again endlessly.
What you will do in the next lab
You create a realm, create a public client and a confidential client each, and create a user. Then in a separate lab you create roles and groups and check how they are reflected in the token, and even try excluding roles with scope.