Keycloak SSO/IdP Setup
Deploy and configure Keycloak for single sign-on with OIDC and SAML integration
What is Keycloak?
Keycloak is an open-source identity and access management (IAM) solution that provides:
- Single Sign-On (SSO): Users authenticate once and access multiple applications
- OpenID Connect (OIDC): Modern OAuth 2.0-based protocol for authentication
- SAML 2.0: Enterprise federation standard
- User Federation: Connect to LDAP, Active Directory, or custom identity providers
- Role-Based Access Control (RBAC): Fine-grained authorization management
Installation with Docker Compose
Prerequisites
- Docker and Docker Compose installed
- A PostgreSQL database (included in the compose stack)
- At least 2GB RAM available
Docker Compose Stack
Create a docker-compose.yml file:
version: '3.8'
services:
postgres:
image: postgres:15-alpine
container_name: keycloak-db
environment:
POSTGRES_DB: keycloak
POSTGRES_USER: keycloak
POSTGRES_PASSWORD: SecurePassword123!
volumes:
- postgres_data:/var/lib/postgresql/data
ports:
- "5432:5432"
healthcheck:
test: ["CMD-SHELL", "pg_isready -U keycloak"]
interval: 10s
timeout: 5s
retries: 5
keycloak:
image: quay.io/keycloak/keycloak:latest
container_name: keycloak
environment:
KEYCLOAK_ADMIN: admin
KEYCLOAK_ADMIN_PASSWORD: AdminPassword123!
KC_DB: postgres
KC_DB_URL: jdbc:postgresql://postgres:5432/keycloak
KC_DB_USERNAME: keycloak
KC_DB_PASSWORD: SecurePassword123!
KC_HOSTNAME: keycloak.example.com
KC_PROXY: reencrypt
KC_HTTP_ENABLED: "true"
ports:
- "8080:8080"
depends_on:
postgres:
condition: service_healthy
volumes:
- keycloak_data:/opt/keycloak/data
command: start --optimized
volumes:
postgres_data:
keycloak_data:Deploy the stack:
docker-compose up -dVerify services are running:
docker-compose psInitial Setup
Access the Admin Console
Navigate to http://localhost:8080/admin and log in with:
- Username:
admin - Password:
AdminPassword123!
Create a Realm
- Click the dropdown next to "Master" in the top-left
- Select "Create Realm"
- Enter realm name:
production - Click "Create"
Create an OIDC Client
- Navigate to Clients → Create client
- Configure:
- Client ID:
myapp - Name:
My Application - Client type:
OpenID Connect
- Client ID:
- Click Next
- Enable: Client authentication
- Click Next
- Set Valid redirect URIs:
http://localhost:3000/callback https://myapp.example.com/callback - Set Valid post logout redirect URIs:
http://localhost:3000 https://myapp.example.com - Click Save
Retrieve Client Credentials
Go to Clients → myapp → Credentials tab and copy the Client Secret (required for backend authentication).
Nginx Reverse Proxy Configuration
Deploy Keycloak behind Nginx with proper header forwarding:
upstream keycloak {
server localhost:8080;
}
server {
listen 80;
server_name keycloak.example.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name keycloak.example.com;
ssl_certificate /etc/letsencrypt/live/keycloak.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/keycloak.example.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
client_max_body_size 20M;
location / {
proxy_pass http://keycloak;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $server_name;
proxy_redirect http:// https://;
# WebSocket support
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}Update KC_HOSTNAME in Docker Compose to match your domain (e.g., keycloak.example.com) when using HTTPS.
Create Users and Roles
Create a User
- Navigate to Users → Add user
- Enter username:
testuser - Enable: Email verified
- Click Create
- Go to Credentials tab
- Set a password (click Set password button)
Create a Role
- Navigate to Roles → Create role
- Enter role name:
app-admin - Click Create
Assign Role to User
- Go to Users → testuser → Role mapping
- Click Assign role → select
app-admin - Click Assign
Test OIDC Flow
Use curl to test the authorization code flow:
# 1. Get authorization code
AUTHORIZE_URL="https://keycloak.example.com/realms/production/protocol/openid-connect/auth"
curl -v "$AUTHORIZE_URL?client_id=myapp&redirect_uri=http://localhost:3000/callback&response_type=code&scope=openid%20profile"
# 2. Exchange code for tokens (replace CODE)
TOKEN_URL="https://keycloak.example.com/realms/production/protocol/openid-connect/token"
curl -X POST $TOKEN_URL \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=authorization_code" \
-d "client_id=myapp" \
-d "client_secret=YOUR_CLIENT_SECRET" \
-d "code=CODE_FROM_STEP_1" \
-d "redirect_uri=http://localhost:3000/callback"
# 3. Decode the returned ID token (use jwt.io or jwt CLI)Protect a Service with oauth2-proxy
Deploy oauth2-proxy as a sidecar to protect your application:
version: '3.8'
services:
myapp:
image: nginx:latest
container_name: myapp
ports:
- "3000:80"
volumes:
- ./index.html:/usr/share/nginx/html/index.html:ro
oauth2-proxy:
image: quay.io/oauth2-proxy/oauth2-proxy:latest
container_name: oauth2-proxy
ports:
- "4180:4180"
environment:
OAUTH2_PROXY_CLIENT_ID: myapp
OAUTH2_PROXY_CLIENT_SECRET: YOUR_CLIENT_SECRET
OAUTH2_PROXY_COOKIE_SECRET: RandomCookieSecret1234567890AB
OAUTH2_PROXY_OIDC_ISSUER_URL: https://keycloak.example.com/realms/production
OAUTH2_PROXY_REDIRECT_URL: https://myapp.example.com/oauth2/callback
OAUTH2_PROXY_UPSTREAMS: http://myapp
OAUTH2_PROXY_HTTP_ADDRESS: 0.0.0.0:4180
OAUTH2_PROXY_SKIP_AUTH_STRIP_HEADERS: "false"
depends_on:
- myappConfigure Nginx to route through oauth2-proxy:
location / {
auth_request /oauth2/auth;
error_page 401 = /oauth2/start;
proxy_pass http://localhost:3000;
proxy_set_header X-User $http_x_auth_request_x_user;
}
location /oauth2/ {
proxy_pass http://localhost:4180;
}Production Deployment Checklist
Before deploying to production, ensure:
- SSL/TLS: Use valid certificates (Let's Encrypt recommended)
- Database: Use a managed PostgreSQL service (AWS RDS, Azure Database, etc.) with automated backups
- KC_HOSTNAME: Set to your production domain
- Admin credentials: Change default
KEYCLOAK_ADMINpassword - Resource limits: Set CPU and memory limits in Docker/Kubernetes
- Scaling: Use Keycloak clustering with a shared database for high availability
- Monitoring: Configure health checks and logging
Clustering for High Availability
Enable Keycloak clustering by modifying the compose stack:
keycloak:
image: quay.io/keycloak/keycloak:latest
environment:
KC_CACHE: ispn
KC_CACHE_CONFIG_FILE: cache-ispn-default.xml
JAVA_OPTS_APPEND: "-Djgroups.dns.query=keycloak"
deploy:
replicas: 3This automatically distributes sessions across multiple Keycloak instances using Infinispan caching.
Next Steps
- Integrate with your application using an OIDC SDK
- Set up user federation with LDAP/Active Directory
- Configure email notifications for password resets
- Implement custom themes matching your brand