TL;DR — Quick Summary

Complete Keycloak guide: install with Docker or Kubernetes, configure realms, OpenID Connect and SAML clients, LDAP federation, RBAC, and high availability.

Keycloak is the leading open-source Identity and Access Management (IAM) solution — it delivers Single Sign-On (SSO), MFA, social login, LDAP/Active Directory federation, and fine-grained authorization using OpenID Connect, OAuth 2.0, and SAML 2.0. This guide covers everything from a production Docker Compose setup to realm configuration, RBAC, identity federation, and high availability clustering.

Prerequisites

  • Docker 25+ and Docker Compose v2 (or a Kubernetes cluster for operator installs).
  • PostgreSQL 15+ for production (embedded H2 is development-only).
  • A reverse proxy (Nginx or Traefik) for TLS termination in production.
  • Basic familiarity with OAuth 2.0 concepts (client, authorization code flow, tokens).

Keycloak Architecture

Keycloak organizes everything into realms — isolated security domains. Each realm contains:

Concept Description
Realm Isolated tenant. Owns users, clients, roles, groups, IdPs
Client Application registered to use Keycloak for auth
User Identity within the realm (local or federated)
Role Permission label. Realm roles span all clients; client roles are scoped
Group Collection of users with inherited role assignments
Identity Provider External IdP (Google, GitHub, SAML, LDAP)
Authentication Flow Configurable pipeline: browser login, OTP, WebAuthn

The master realm is the super-admin realm — use it only for managing other realms, never for application users.


Step 1: Install Keycloak with Docker Compose

This is the recommended production-ready starting point. Save as docker-compose.yml:

version: "3.9"
services:
  postgres:
    image: postgres:15
    environment:
      POSTGRES_DB: keycloak
      POSTGRES_USER: keycloak
      POSTGRES_PASSWORD: changeme
    volumes:
      - postgres_data:/var/lib/postgresql/data

  keycloak:
    image: quay.io/keycloak/keycloak:24.0
    command: start
    environment:
      KC_DB: postgres
      KC_DB_URL: jdbc:postgresql://postgres/keycloak
      KC_DB_USERNAME: keycloak
      KC_DB_PASSWORD: changeme
      KC_HOSTNAME: auth.example.com
      KC_PROXY: edge          # TLS terminated at reverse proxy
      KEYCLOAK_ADMIN: admin
      KEYCLOAK_ADMIN_PASSWORD: adminpass
    ports:
      - "8080:8080"
    depends_on:
      - postgres

volumes:
  postgres_data:
docker compose up -d
# Access Admin Console at http://localhost:8080

For Kubernetes, use the official Keycloak Operator:

kubectl apply -f https://raw.githubusercontent.com/keycloak/keycloak-k8s-resources/24.0.0/kubernetes/keycloaks.k8s.keycloak.org-v1.yml
kubectl apply -f https://raw.githubusercontent.com/keycloak/keycloak-k8s-resources/24.0.0/kubernetes/keycloak-operator.yml

Step 2: Realm Configuration

After logging in to the Admin Console:

  1. Click the realm dropdown (top-left) → Create Realm.
  2. Set a name (e.g., myapp), enable it, click Create.

Key realm settings to configure:

Setting Recommended value
Display name Your brand name
Login theme keycloak (or custom)
Require SSL external requests (production)
SSO Session Idle 30 minutes
Access Token Lifespan 5 minutes
Refresh Token Lifespan 30 minutes

Configure SMTP under Realm Settings → Email for password reset and verification emails.


Step 3: OpenID Connect Client Configuration

Go to ClientsCreate client:

  • Client type: OpenID Connect
  • Client ID: myapp-client
  • Client authentication: ON (confidential) for server-side apps; OFF (public) for SPAs/mobile
  • Valid redirect URIs: https://myapp.example.com/callback
  • Web origins: https://myapp.example.com (enables CORS)

Confidential vs Public Clients

Feature Confidential Public
Has client secret Yes No
Use case Server-side (Node, .NET, Python) SPA, mobile app
Auth code flow With client secret With PKCE
Risk if compromised High — rotate secret Low — secret-less

Protocol Mappers

Add mappers to include custom claims in tokens: Clients → your client → Client ScopesAdd mapper. Common mappers: User Attribute, Role, Group Membership, Audience.


Step 4: Role-Based Access Control (RBAC)

Realm Roles vs Client Roles

Realm roles apply across all clients in the realm. Client roles are scoped to a specific client:

# Create a realm role via kcadm.sh
kcadm.sh config credentials \
  --server http://localhost:8080 \
  --realm master \
  --user admin --password adminpass

kcadm.sh create roles -r myapp -s name=app-admin
kcadm.sh create roles -r myapp -s name=app-user

Groups and Role Mappings

  1. RealmGroupsCreate group → name it Administrators.
  2. Open the group → Role MappingAssign role → select app-admin.
  3. Add users to the group — they inherit the role automatically.

Composite Roles

A composite role bundles other roles. Create a superuser realm role, then add app-admin and app-user as composites — any user with superuser gets both.


Step 5: Identity Federation

Social Login (Google, GitHub, Microsoft)

Identity ProvidersAdd provider → select Google:

  1. Create an OAuth 2.0 app in Google Cloud Console.
  2. Set Client ID and Client Secret from Google.
  3. Set Redirect URI back to Keycloak: https://auth.example.com/realms/myapp/broker/google/endpoint.
  4. Enable Trust Email if Google-verified emails should be auto-trusted.

LDAP / Active Directory Federation

User FederationAdd providerLDAP:

Setting Value
Vendor Active Directory
Connection URL ldap://ad.corp.example.com
Bind DN CN=svc-keycloak,OU=ServiceAccounts,DC=corp,DC=example,DC=com
Users DN OU=Users,DC=corp,DC=example,DC=com
Sync Mode FORCE (attributes always overwritten from LDAP)

Run Synchronize all users to import AD users into Keycloak. LDAP group mapper syncs AD groups to Keycloak groups automatically.


Step 6: Authentication Flows and MFA

Browser Flow Customization

AuthenticationFlowsbrowserDuplicate to create a custom flow. Add OTP Form as REQUIRED after username/password to enforce TOTP for all users.

WebAuthn / Passkeys

Keycloak 22+ supports WebAuthn out of the box:

  1. AuthenticationPoliciesWebAuthn Policy — set Relying Party ID to your domain.
  2. Add WebAuthn Authenticator to your browser flow.
  3. Users register their passkey on first login — no TOTP app needed.

Required Actions

Under Users → select user → Required User Actions, you can force:

  • CONFIGURE_TOTP — forces OTP setup on next login.
  • UPDATE_PASSWORD — forces password reset.
  • VERIFY_EMAIL — sends verification email.

Fine-Grained Authorization (UMA 2.0)

For resource-level permissions, enable Authorization on a confidential client:

  • Resources — define protected resources (e.g., /api/reports).
  • Scopes — define actions (read, write, delete).
  • Policies — rules based on roles, groups, JS scripts, or time.
  • Permissions — bind resources+scopes to policies.

Clients query the Token Endpoint with grant_type=urn:ietf:params:oauth:grant-type:uma-ticket to get a Requesting Party Token (RPT) with permission claims.


High Availability Setup

For production clusters, run 2+ Keycloak nodes sharing PostgreSQL and an Infinispan distributed cache:

environment:
  KC_CACHE: ispn
  KC_CACHE_STACK: jdbc-ping   # auto-discovery via DB
  KC_DB: postgres
  KC_DB_URL: jdbc:postgresql://pgpool/keycloak  # pgBouncer/pgPool

Load balancer requirements:

  • Enable sticky sessions (route by session cookie AUTH_SESSION_ID).
  • Health check endpoint: GET /health/ready (returns 200 when node is ready).
  • Drain connections gracefully — Keycloak replicates sessions across nodes.

Gotchas and Edge Cases

Issue Cause Fix
Tokens too large Too many roles/groups in token Use roles claim selectively; filter with mappers
CORS errors Web origins not set Add exact origin in client Web Origins field
LDAP sync fails Bind DN lacks read permissions Grant Read Members of a Group in AD
Redirect URI mismatch Trailing slash or query string Keycloak does exact match — add all URI variants
Clock skew errors Server time drift Sync NTP on all Keycloak and app nodes
Admin console 403 Wrong realm Ensure you’re logged into master realm for realm management

Keycloak vs Alternatives

Feature Keycloak Authentik Authelia Auth0 Okta FusionAuth
Open-source Yes Yes Yes No No Partial
Self-hosted Yes Yes Yes No No Yes
SAML 2.0 Yes Yes No Yes Yes Yes
LDAP federation Yes Yes No Yes Yes Yes
Fine-grained authz Yes (UMA) No No Yes (paid) Yes (paid) Partial
Complexity High Medium Low Low Low Medium
Best for Enterprise SSO Modern web apps Reverse proxy MFA SaaS/startup Enterprise Mid-market

Troubleshooting

Problem Solution
“Invalid redirect_uri” Check client’s Valid Redirect URIs — must be exact match including trailing slash
“Client secret not valid” Regenerate secret in Clients → Credentials → Regenerate
Login loop Check that KC_HOSTNAME matches the actual URL; proxy header misconfiguration
Email not sending Verify SMTP config in Realm Settings → Email → Test Connection
Users not synced from LDAP Check bind credentials; run Synchronize Changed Users from User Federation

Summary

  • Realms isolate tenants; always use a dedicated realm for applications.
  • Confidential clients use client secrets; public clients use PKCE.
  • Groups with role mappings scale RBAC — avoid assigning roles directly to users.
  • LDAP sync with FORCE mode keeps AD attributes authoritative.
  • For HA, use KC_CACHE=ispn with jdbc-ping — no ZooKeeper or Kubernetes required.
  • Automate everything via kcadm.sh or the Admin REST API for GitOps workflows.