How to setup roles in Keycloak

Posted by

Limited Time Offer!

For Less Than the Cost of a Starbucks Coffee, Access All DevOpsSchool Videos on YouTube Unlimitedly.
Master DevOps, SRE, DevSecOps Skills!

Enroll Now

A) Create / prepare your Realm

  1. Sign in to Keycloak Admin Console.
  2. Top-left realm selector โ†’ Create realm (e.g., acme).

B) Define your roles (admin / manager / user)

You can use Realm Roles (recommended for app-wide roles) or Client Roles (scoped to a single client). Weโ€™ll use Realm Roles.

  1. In left nav, Roles โ†’ Add role:
    • Create admin, manager, user.
  2. (Optional but tidy) Groups โ†’ Add groups admins, managers, users.
    • Inside each group โ†’ Role mappings โ†’ Assign role โ†’ add the matching realm role.
    • Later, just put users in groups; theyโ€™ll inherit the role.

Result: your tokens can include these realm roles under realm_access.roles.


C) Create the OIDC Client for Laravel

You have two safe choices. Pick one:

Option 1 โ€” Public client + PKCE (no secret)

  • Good when you donโ€™t want to store a secret or might ever do a browser-based flow.

Option 2 โ€” Confidential client (has a secret)

  • Also fine for server-side Laravel Socialite (secret stays on your server).

Steps (common; Iโ€™ll note the one-line difference for each option):

  1. Left nav Clients โ†’ Create client
    • Client type: OpenID Connect
    • Client ID: laravel-app (must match KEYCLOAK_CLIENT_ID in .env)
    • Name: (anything)
    • Always display in UI: your choice
    • Click Next
  2. Capability config:
    • Client authentication:
      • OFF for Public + PKCE (Option 1)
      • ON for Confidential (Option 2)
    • Authorization: OFF (not needed)
    • Click Next
  3. Login settings:
    • Valid redirect URIs: add your Laravel callback(s)
      • http://localhost:8000/auth/callback
      • https://yourapp.example.com/auth/callback
    • Web origins: add exact origins youโ€™ll use (e.g., http://localhost:8000, https://yourapp.example.com). Avoid * in prod.
    • Root URL (optional but nice): your siteโ€™s base URL.
    • Save.
  4. If you chose Option 1 (Public + PKCE):
    • Client โ†’ Advanced (or Settings, depending on version) โ†’ ensure PKCE is Required, Method = S256.
  5. If you chose Option 2 (Confidential):
    • Client โ†’ Credentials tab โ†’ copy the Client Secret to your Laravel .env (KEYCLOAK_CLIENT_SECRET).

Make sure Standard Flow (Authorization Code) is enabled; it is enabled by default for new OIDC clients. Weโ€™re not using Implicit or Direct Access Grants.


D) Ensure roles are sent in tokens

Keycloak includes claims based on Client Scopes.

  1. Client scopes (left nav) โ†’ confirm a built-in scope named roles exists (it normally does).
    • Inside it thereโ€™s a mapper for realm roles (go to โ€œMappersโ€ and see โ€œrealm rolesโ€ / โ€œrolesโ€).
  2. Go to your Client โ†’ Client scopes:
    • Under Assigned default client scopes, ensure roles is present.
    • If not, Add client scope โ†’ pick roles.
  3. Keep profile and email in default scopes as well (usually already there).

Result: your ID token and Access token will include roles.

  • Realm roles โ†’ realm_access.roles
  • If you ever use client roles โ†’ resource_access[clientId].roles

Your Laravel callback code (from earlier) merges both; youโ€™re covered either way.


E) Create users and assign roles

  1. Users โ†’ Add user โ†’ fill username, email, etc. Save.
  2. Credentials tab โ†’ set password (toggle temporary off if you want).
  3. Assign role:
    • Either Role mappings โ†’ Assign role โ†’ pick admin/manager/user, Add.
    • Or put the user in a Group that already has the role.

Logins via social providers (Google/Apple) configured in Keycloak can also be mapped to these rolesโ€”see Section G.


F) Double-check client settings against Laravel .env

In Laravel you set:

KEYCLOAK_BASE_URL=http://localhost:8080      # or https://kc.yourdomain.com
KEYCLOAK_REALM=acme
KEYCLOAK_CLIENT_ID=laravel-app
KEYCLOAK_CLIENT_SECRET=   # only for confidential clients
KEYCLOAK_REDIRECT_URI=http://localhost:8000/auth/callback

In Keycloak client:

  • Client ID = laravel-app
  • Redirect URI includes /auth/callback
  • Web origins include your appโ€™s origins
  • If Public client: PKCE required (S256)
  • If Confidential: Client secret matches .env

G) (Optional) Add Google/Apple login to Keycloak (federated IdP)

If you want users to log in with Google/Apple into Keycloak (and still get your Laravel roles):

  1. Identity Providers โ†’ Add provider โ†’ choose Google (or Apple).
  2. Enter Google/Apple Client ID/Secret (from their developer consoles).
  3. Save. Try login from the Keycloak login page โ†’ youโ€™ll see a Google/Apple button.
  4. Map to roles:
    • Use User Attribute โ†’ Role approach or Group Mapper:
      • Create a Group (e.g., admins) with role admin attached.
      • In Identity Providers โ†’ Mappers, add a mapper that puts users into that group based on an IdP attribute (e.g., email domain).
      • Alternatively, run a small post-login admin action to assign roles manually.

This keeps all SSO sources behind Keycloak; Laravel just sees a standard OIDC login.


H) (Optional) Single Logout (SLO)

If you want to log users out of Keycloak too (not just Laravel session):

  • Use Keycloakโ€™s end-session endpoint: {KEYCLOAK_BASE_URL}/realms/{REALM}/protocol/openid-connect/logout ?post_logout_redirect_uri={APP_URL_ENCODED} &id_token_hint={ID_TOKEN}
  • You already capture id_token in the callback; you can stash it in session and call this on logout.
  • If you skip SLO, your app will log out locally, but the Keycloak session remains until it expires.

I) Quick test flow

  1. Start Keycloak (dev example): docker run -p 8080:8080 \ -e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=admin \ quay.io/keycloak/keycloak:25.0.6 start-dev
  2. Create realm, roles, client, user (as above).
  3. Run Laravel: php artisan serve
  4. Visit http://localhost:8000/login โ†’ you should be redirected to Keycloak.
  5. Log in with the test user (e.g., role manager) โ†’ you should land on /dashboard and only routes allowed by role:manager should work.

J) Troubleshooting

  • Redirect URI mismatch โ†’ Ensure the exact URI (including scheme, host, port, path) is in โ€œValid redirect URIs.โ€
  • 403 on protected routes โ†’ Token didnโ€™t include roles:
    • Confirm roles client scope is assigned to the client.
    • Confirm the user actually has admin/manager/user (Role mappings or via Group).
    • Confirm you request the roles scope in Laravel (->scopes(['openid','profile','email','roles'])).
  • CORS errors โ†’ Add your site origin(s) under Web origins.
  • Time/clock skew โ†’ If tokens seem โ€œnot yet valid,โ€ ensure Keycloak and server time are in sync (NTP).
  • Confidential client โ†’ If code exchange fails, re-check the Client Secret in your .env.

Thatโ€™s it

Once these steps are done, your Laravel appโ€™s Socialite flow will receive an ID token containing realm_access.roles (and client roles if you ever use them), and your middleware will gate /admin, /manager, /user accordingly.

If you want, I can also give you a minimal Keycloak realm export (JSON) with the roles, a demo client pre-configured for http://localhost:8000/auth/callback, and a sample userโ€”ready to import.

Leave a Reply

Your email address will not be published. Required fields are marked *

0
Would love your thoughts, please comment.x
()
x