Keycloak Installation for Single Sign-On
Keycloak is a powerful open-source identity and access management platform that provides Single Sign-On (SSO), OAuth2/OIDC, and SAML support, allowing you to centralize authentication for all your applications from a self-hosted server. This guide covers deploying Keycloak, configuring realms and clients, setting up OAuth2/OIDC and SAML, and integrating user federation with existing directories.
Prerequisites
- Ubuntu 20.04+ or CentOS/Rocky Linux 8+
- Docker (for containerized deployment) or Java 17+
- PostgreSQL or MySQL for production (H2 embedded for testing only)
- 2GB+ RAM (4GB+ recommended for production)
- A domain name for the Keycloak server
Installing Keycloak with Docker
mkdir -p ~/keycloak && cd ~/keycloak
cat > docker-compose.yml << 'EOF'
services:
postgres:
image: postgres:16
container_name: keycloak-db
environment:
POSTGRES_DB: keycloak
POSTGRES_USER: keycloak
POSTGRES_PASSWORD: keycloak_db_password
volumes:
- postgres-data:/var/lib/postgresql/data
restart: unless-stopped
keycloak:
image: quay.io/keycloak/keycloak:latest
container_name: keycloak
depends_on:
- postgres
command: start
environment:
KC_DB: postgres
KC_DB_URL: jdbc:postgresql://postgres/keycloak
KC_DB_USERNAME: keycloak
KC_DB_PASSWORD: keycloak_db_password
KC_HOSTNAME: auth.example.com
KC_PROXY: edge # Trust reverse proxy headers
KC_HTTP_ENABLED: "true" # HTTP for behind-proxy setup
KEYCLOAK_ADMIN: admin
KEYCLOAK_ADMIN_PASSWORD: change_this_admin_password
ports:
- "8080:8080"
restart: unless-stopped
volumes:
postgres-data:
EOF
docker compose up -d
docker compose logs -f keycloak
Wait for Keycloak to start (about 60-90 seconds), then access:
- Admin console:
http://your-server:8080/admin - Account portal:
http://your-server:8080/realms/master/account
Installing Keycloak on Bare Linux
# Install Java 17
sudo apt-get install -y openjdk-17-jdk
# Download Keycloak
KEYCLOAK_VERSION=24.0.4
wget "https://github.com/keycloak/keycloak/releases/download/${KEYCLOAK_VERSION}/keycloak-${KEYCLOAK_VERSION}.tar.gz"
sudo tar -xzf keycloak-${KEYCLOAK_VERSION}.tar.gz -C /opt/
sudo ln -s /opt/keycloak-${KEYCLOAK_VERSION} /opt/keycloak
sudo useradd -r -s /sbin/nologin keycloak
sudo chown -R keycloak:keycloak /opt/keycloak*
# Configure database and settings
sudo tee /opt/keycloak/conf/keycloak.conf << 'EOF'
db=postgres
db-url=jdbc:postgresql://localhost/keycloak
db-username=keycloak
db-password=keycloak_db_password
hostname=auth.example.com
proxy=edge
http-enabled=true
http-port=8080
EOF
# Build Keycloak (required before first start)
sudo -u keycloak /opt/keycloak/bin/kc.sh build
# Create systemd service
sudo tee /etc/systemd/system/keycloak.service << 'EOF'
[Unit]
Description=Keycloak Identity Provider
After=network.target postgresql.service
[Service]
User=keycloak
Group=keycloak
EnvironmentFile=-/etc/default/keycloak
ExecStart=/opt/keycloak/bin/kc.sh start
Restart=on-failure
RestartSec=10
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target
EOF
# Set admin credentials as environment variables
sudo tee /etc/default/keycloak << 'EOF'
KEYCLOAK_ADMIN=admin
KEYCLOAK_ADMIN_PASSWORD=change_this_admin_password
EOF
sudo chmod 600 /etc/default/keycloak
sudo systemctl daemon-reload
sudo systemctl enable keycloak
sudo systemctl start keycloak
Realm Configuration
A realm is an isolated namespace for users, clients, and identity providers. Create separate realms per organization or environment:
- Log into the Admin Console at
http://your-server:8080/admin - Click the realm dropdown (top-left, shows "master") > Create Realm
- Enter name:
myappand click Create
Via CLI (kcadm.sh):
# Log into admin CLI
/opt/keycloak/bin/kcadm.sh config credentials \
--server http://localhost:8080 \
--realm master \
--user admin \
--password change_this_admin_password
# Create a realm
/opt/keycloak/bin/kcadm.sh create realms \
-s realm=myapp \
-s displayName="My Application" \
-s enabled=true \
-s registrationAllowed=false \
-s resetPasswordAllowed=true \
-s loginWithEmailAllowed=true
Creating Clients for Applications
A client represents an application that uses Keycloak for authentication:
# Create an OIDC client for a web app
/opt/keycloak/bin/kcadm.sh create clients \
-r myapp \
-s clientId=my-webapp \
-s name="My Web Application" \
-s enabled=true \
-s publicClient=false \
-s 'redirectUris=["https://app.example.com/*"]' \
-s 'webOrigins=["https://app.example.com"]' \
-s serviceAccountsEnabled=true
In the UI:
- Go to Clients > Create Client
- Select OpenID Connect
- Set Client ID:
my-webapp - Set Valid redirect URIs:
https://app.example.com/* - Under Credentials, copy the Client Secret
OAuth2 and OIDC Integration
Integration endpoints for your realm:
# Discovery document (contains all endpoint URLs)
curl https://auth.example.com/realms/myapp/.well-known/openid-configuration
# Key endpoints:
# Authorization: /realms/myapp/protocol/openid-connect/auth
# Token: /realms/myapp/protocol/openid-connect/token
# Userinfo: /realms/myapp/protocol/openid-connect/userinfo
# JWKS: /realms/myapp/protocol/openid-connect/certs
# Logout: /realms/myapp/protocol/openid-connect/logout
Example authorization code flow:
# Step 1: Redirect user to authorization endpoint
# https://auth.example.com/realms/myapp/protocol/openid-connect/auth?
# client_id=my-webapp&
# response_type=code&
# scope=openid email profile&
# redirect_uri=https://app.example.com/callback&
# state=random-state-value
# Step 2: Exchange authorization code for tokens
curl -X POST https://auth.example.com/realms/myapp/protocol/openid-connect/token \
-d "grant_type=authorization_code" \
-d "client_id=my-webapp" \
-d "client_secret=YOUR_CLIENT_SECRET" \
-d "code=AUTHORIZATION_CODE" \
-d "redirect_uri=https://app.example.com/callback"
# Step 3: Use access token to call your API
curl https://api.example.com/protected \
-H "Authorization: Bearer ACCESS_TOKEN"
Client credentials flow (service-to-service):
curl -X POST https://auth.example.com/realms/myapp/protocol/openid-connect/token \
-d "grant_type=client_credentials" \
-d "client_id=my-service" \
-d "client_secret=YOUR_CLIENT_SECRET"
SAML Integration
For applications that require SAML 2.0 instead of OIDC:
- Create a client with Client Protocol: saml
- Set Valid Redirect URIs to your application's SAML endpoint
- Download the SP metadata from Keycloak and import into your app
# Get Keycloak's SAML IDP metadata
curl https://auth.example.com/realms/myapp/protocol/saml/descriptor
# Key SAML endpoints:
# SSO: /realms/myapp/protocol/saml
# SLO: /realms/myapp/protocol/saml (with LogoutRequest)
User Federation with LDAP
Connect Keycloak to an existing LDAP/AD directory:
- In the realm, go to User Federation > Add Provider > LDAP
- Configure:
- Vendor: Active Directory / OpenLDAP / Other
- Connection URL:
ldaps://ldap.example.com - Bind DN:
cn=readonly,dc=example,dc=com - Bind Credential: readonly password
- Users DN:
ou=users,dc=example,dc=com
- Click Test Connection and Test Authentication
- Click Save, then Sync All Users
Via CLI:
/opt/keycloak/bin/kcadm.sh create components \
-r myapp \
-s name="ldap-provider" \
-s providerId=ldap \
-s providerType=org.keycloak.storage.UserStorageProvider \
-s 'config.vendor=["other"]' \
-s 'config.connectionUrl=["ldaps://ldap.example.com"]' \
-s 'config.bindDn=["cn=readonly,dc=example,dc=com"]' \
-s 'config.bindCredential=["readonly_password"]' \
-s 'config.usersDn=["ou=users,dc=example,dc=com"]'
Nginx Reverse Proxy
sudo tee /etc/nginx/sites-available/keycloak << 'EOF'
server {
listen 80;
server_name auth.example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name auth.example.com;
ssl_certificate /etc/letsencrypt/live/auth.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/auth.example.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
location / {
proxy_pass http://127.0.0.1:8080;
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_buffer_size 128k;
proxy_buffers 4 256k;
proxy_busy_buffers_size 256k;
}
}
EOF
sudo ln -s /etc/nginx/sites-available/keycloak /etc/nginx/sites-enabled/
sudo certbot --nginx -d auth.example.com
sudo nginx -t && sudo systemctl reload nginx
Troubleshooting
Admin console not accessible
# Check Keycloak is running
docker logs keycloak --tail 50
sudo systemctl status keycloak
# Verify port is listening
ss -tlnp | grep 8080
"Invalid redirect_uri" error
# Add the exact redirect URI to the client's valid redirect URIs
# Wildcards: https://app.example.com/* — note trailing /*
Database connection failed
# Test PostgreSQL connection
psql -h localhost -U keycloak -d keycloak -c "\l"
# Check Docker network
docker exec keycloak ping postgres
LDAP sync fails
# Test LDAP connection from Keycloak
# Admin Console > User Federation > your-ldap-provider > Test Connection
# Check LDAP bind credentials
ldapwhoami -x -H ldaps://ldap.example.com \
-D "cn=readonly,dc=example,dc=com" -W
Conclusion
Keycloak provides a production-ready SSO platform that handles OAuth2, OIDC, and SAML for all your self-hosted applications through a single identity provider. With realm isolation, LDAP federation, and a comprehensive admin API, it scales from simple single-application deployments to organization-wide identity management serving dozens of applications.


