Software & Configuration

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 -d

Verify services are running:

docker-compose ps

Initial Setup

Access the Admin Console

Navigate to http://localhost:8080/admin and log in with:

  • Username: admin
  • Password: AdminPassword123!

Create a Realm

  1. Click the dropdown next to "Master" in the top-left
  2. Select "Create Realm"
  3. Enter realm name: production
  4. Click "Create"

Create an OIDC Client

  1. Navigate to ClientsCreate client
  2. Configure:
    • Client ID: myapp
    • Name: My Application
    • Client type: OpenID Connect
  3. Click Next
  4. Enable: Client authentication
  5. Click Next
  6. Set Valid redirect URIs:
    http://localhost:3000/callback
    https://myapp.example.com/callback
  7. Set Valid post logout redirect URIs:
    http://localhost:3000
    https://myapp.example.com
  8. Click Save

Retrieve Client Credentials

Go to ClientsmyappCredentials 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

  1. Navigate to UsersAdd user
  2. Enter username: testuser
  3. Enable: Email verified
  4. Click Create
  5. Go to Credentials tab
  6. Set a password (click Set password button)

Create a Role

  1. Navigate to RolesCreate role
  2. Enter role name: app-admin
  3. Click Create

Assign Role to User

  1. Go to UserstestuserRole mapping
  2. Click Assign role → select app-admin
  3. 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:
      - myapp

Configure 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_ADMIN password
  • 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: 3

This 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

On this page