Keycloak Unified Identity in Practice: SSO Deployment and Configuration
Keycloak is an open-source identity and access management platform supporting OIDC and SAML. This guide covers deploy, Realm setup, client integration, and hardening to stand up enterprise SSO and access control.
Keycloak SSO is enterprise unified-identity infrastructure. More internal systems means more independently managed passwords and a larger weak-password / credential-leak surface. Keycloak is an open-source IAM platform. Via OIDC/SAML, users log in once and reach every connected app, with MFA and session policy on the side. This guide covers full deploy and integration.
Scope
- Multiple enterprise web apps that need a single login entry and account store
- OIDC or SAML identity for third-party applications
- Role-differentiated access control
- Central password policy, session timeout, and MFA
Prerequisites
- One Linux server (2C4G or better) with Docker and Docker Compose
- Planned DNS, e.g. `sso.example.com`
- TLS certificate (Keycloak production requires HTTPS)
- OIDC basics: Client, Realm, Access Token
How It Works
The core object is the Realm: an isolated tenant holding users, clients, and roles. Apps register as Clients in a Realm. On access, the user is redirected to the Keycloak login page. After auth, Keycloak issues an ID Token and Access Token. The app verifies signatures with the JWKS public keys and trusts the identity. Versus per-app login, SSO collapses authentication onto one platform so password policy, MFA, and audit are applied once.
Procedure
Step 1: Deploy Keycloak with Docker Compose
Create `docker-compose.yml`:
version: "3.8"
services:
keycloak:
image: quay.io/keycloak/keycloak:24.0
container_name: keycloak
command: start --optimized
environment:
KC_DB: postgres
KC_DB_URL: jdbc:postgresql://db:5432/keycloak
KC_DB_USERNAME: keycloak
KC_DB_PASSWORD: Kc@2026!StrongPass
KEYCLOAK_ADMIN: admin
KEYCLOAK_ADMIN_PASSWORD: Admin@2026!StrongPass
KC_HOSTNAME: sso.example.com
KC_HTTPS_CERTIFICATE_FILE: /certs/fullchain.pem
KC_HTTPS_CERTIFICATE_KEY_FILE: /certs/privkey.pem
ports:
- "8443:8443"
volumes:
- /etc/letsencrypt/live/sso.example.com:/certs:ro
depends_on:
- db
db:
image: postgres:16
environment:
POSTGRES_DB: keycloak
POSTGRES_USER: keycloak
POSTGRES_PASSWORD: Kc@2026!StrongPass
volumes:
- pgdata:/var/lib/postgresql/data
volumes:
pgdata:
Start and verify:
docker compose up -d
# After startup completes, access the admin console
curl -k -s -o /dev/null -w "%{http_code}" https://127.0.0.1:8443/realms/master
Step 2: Create Realm and client
Log in as admin at `https://sso.example.com:8443`:
- Top-left master dropdown → Create realm. Name: `corp`. Click Create
- Clients → Create client. Client ID: `erp-web`. Client type: `OpenID Connect`
- Capability config: enable Standard flow (authorization code). Redirect URIs: `https://erp.example.com/callback`
- Save. Credentials tab: copy the Client secret
Step 3: Create a test user and role
# Create a user via the Admin REST API (replace TOKEN with an access token obtained using client credentials)
curl -X POST "https://sso.example.com:8443/admin/realms/corp/users" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"username":"zhangsan","enabled":true,"email":"zhangsan@example.com","credentials":[{"type":"password","value":"User@2026!","temporary":false}]}'
In the admin UI, create an `erp-admin` role under Realm roles and assign it on the user detail page.
Step 4: Application-side OIDC integration
Frontend example with oidc-client-js:
import { UserManager } from "oidc-client-ts";
const mgr = new UserManager({
authority: "https://sso.example.com:8443/realms/corp",
client_id: "erp-web",
client_secret: "YOUR_CLIENT_SECRET",
redirect_uri: "https://erp.example.com/callback",
response_type: "code",
scope: "openid profile email",
});
// Trigger the login redirect
mgr.signinRedirect();
// Complete token exchange on the callback page
mgr.signinRedirectCallback().then(user => {
console.log("Logged-in user:", user.profile.preferred_username);
});
Verification
# Verify the Realm public configuration is reachable (OIDC discovery endpoint)
curl -s https://sso.example.com:8443/realms/corp/.well-known/openid-configuration | python3 -m json.tool | head -20
# Verify the JWKS public-key endpoint returns successfully
curl -s -o /dev/null -w "%{http_code}" https://sso.example.com:8443/realms/corp/protocol/openid-connect/certs
# Unauthenticated access to a protected app should redirect to the Keycloak login page
curl -s -o /dev/null -w "%{redirect_url}" http://erp.example.com/
FAQ
FAQ 1: Token request returns invalid_client?
Usually a Client secret mismatch or the flow is not enabled. Check Clients → erp-web → Credentials against the code. Confirm Client authentication is on. Public clients (no secret) must not set client_secret.
FAQ 2: How to reduce default-admin risk in production?
Create a dedicated Realm admin; do not use the master-realm admin day to day. Enable MFA for admin (Authentication → Required actions → Configure OTP). Bind the admin console to an internal address or restrict source IPs with a firewall. Periodically review Realm session counts and anomalous login logs.
Summary
Keycloak collapses enterprise identity onto a single SSO entry: Realm isolates tenants, Client attaches apps, roles gate access. OIDC integrates with any language. Production: HTTPS, strong passwords, MFA, PostgreSQL backups. New apps follow least privilege—only required scopes and roles—to cut credential-leak and lateral-movement risk.