Configure Keycloak as a SAML identity provider for enterprise SSO, integrate with external identity providers, and implement secure SAML service provider connections with attribute mapping.
Prerequisites
- Root access to server
- Domain name with DNS control
- SSL certificates
- PostgreSQL knowledge
- Basic LDAP/Active Directory understanding
What this solves
SAML (Security Assertion Markup Language) integration allows your enterprise applications to authenticate users through centralized identity providers like Active Directory, Okta, or Azure AD. This tutorial configures Keycloak as both a SAML identity provider and service provider, enabling seamless single sign-on across your application ecosystem with proper attribute mapping and user federation.
Step-by-step configuration
Install and start Keycloak
First, install and configure Keycloak with PostgreSQL database backend for production deployment.
sudo apt update
sudo apt install -y openjdk-17-jdk wget postgresql postgresql-contrib
Download and configure Keycloak
Download the latest Keycloak release and set up the directory structure with proper permissions.
cd /opt
sudo wget https://github.com/keycloak/keycloak/releases/download/23.0.3/keycloak-23.0.3.tar.gz
sudo tar -xzf keycloak-23.0.3.tar.gz
sudo mv keycloak-23.0.3 keycloak
sudo useradd -r -s /bin/false keycloak
sudo chown -R keycloak:keycloak /opt/keycloak
Configure PostgreSQL database
Create a dedicated database and user for Keycloak with proper authentication settings.
sudo -u postgres psql -c "CREATE DATABASE keycloak;"
sudo -u postgres psql -c "CREATE USER keycloak WITH PASSWORD 'your_secure_password';"
sudo -u postgres psql -c "GRANT ALL PRIVILEGES ON DATABASE keycloak TO keycloak;"
Configure Keycloak database connection
Set up the Keycloak configuration file with database connection parameters and production settings.
# Database configuration
db=postgres
db-url=jdbc:postgresql://localhost/keycloak
db-username=keycloak
db-password=your_secure_password
Hostname configuration
hostname=your.keycloak.domain.com
hostname-strict=false
HTTP/HTTPS configuration
http-enabled=true
http-port=8080
https-port=8443
Proxy configuration for reverse proxy
proxy=edge
Logging
log-level=INFO
log-file=/opt/keycloak/data/log/keycloak.log
Create systemd service
Configure Keycloak to run as a systemd service with automatic startup and proper resource limits.
[Unit]
Description=Keycloak Identity and Access Management
After=network.target postgresql.service
Requires=postgresql.service
[Service]
Type=notify
User=keycloak
Group=keycloak
WorkingDirectory=/opt/keycloak
ExecStart=/opt/keycloak/bin/kc.sh start
Restart=always
RestartSec=30
TimeoutStartSec=300
TimeoutStopSec=30
Resource limits
LimitNOFILE=65536
LimitNPROC=4096
Environment variables
Environment=KEYCLOAK_ADMIN=admin
Environment=KEYCLOAK_ADMIN_PASSWORD=admin_secure_password
Environment=JAVA_OPTS="-Xms2g -Xmx4g -XX:MetaspaceSize=96M -XX:MaxMetaspaceSize=256m"
[Install]
WantedBy=multi-user.target
Build and start Keycloak
Build Keycloak with the database configuration and start the service.
sudo -u keycloak /opt/keycloak/bin/kc.sh build
sudo systemctl daemon-reload
sudo systemctl enable --now keycloak
sudo systemctl status keycloak
Configure SAML identity provider
Access the Keycloak admin console and configure it as a SAML identity provider for external applications.
Navigate to your realm and configure SAML client settings:
# 1. Create new client
Client ID: your-application-saml
Protocol: saml
Client SAML Endpoint: https://your-app.com/saml/acs
2. Configure SAML settings
Sign Documents: ON
Sign Assertions: ON
Signature Algorithm: RSA_SHA256
SAML Signature Key Name: KEY_ID
Canonicalization Method: EXCLUSIVE
3. Set Valid Redirect URIs
https://your-app.com/*
4. Configure attribute mappers
Create SAML attribute mappers
Configure attribute mapping to pass user information to service providers through SAML assertions.
In the Keycloak admin console, go to your SAML client and add these mappers:
# Email mapper
Name: email
Mapper Type: User Attribute
User Attribute: email
SAML Attribute Name: email
SAML Attribute NameFormat: Basic
First Name mapper
Name: firstName
Mapper Type: User Attribute
User Attribute: firstName
SAML Attribute Name: first_name
SAML Attribute NameFormat: Basic
Last Name mapper
Name: lastName
Mapper Type: User Attribute
User Attribute: lastName
SAML Attribute Name: last_name
SAML Attribute NameFormat: Basic
Roles mapper
Name: roles
Mapper Type: Role list
Role attribute name: roles
Friendly Name: Roles
SAML Attribute NameFormat: Basic
Single Role Attribute: false
Configure external SAML identity provider
Set up Keycloak to federate authentication with an external SAML identity provider like Azure AD or Okta.
In Identity Providers section, add a new SAML v2.0 provider:
# Basic Settings
Alias: azure-ad-saml
Display Name: Azure Active Directory
Enabled: ON
Trust Email: ON
Store Tokens: ON
Store Tokens Readable: ON
SAML Configuration
Service Provider Entity ID: https://your.keycloak.domain.com/realms/your-realm
Single Sign-On Service URL: https://login.microsoftonline.com/tenant-id/saml2
Single Logout Service URL: https://login.microsoftonline.com/tenant-id/saml2
Backchannel Logout: ON
Signature and Encryption
Want AuthnRequests Signed: ON
Want Assertions Signed: ON
Want Assertions Encrypted: OFF
Signature Algorithm: RSA_SHA256
SAML Signature Key Name: KEY_ID
Configure identity provider mappers
Map attributes from the external SAML identity provider to Keycloak user attributes.
# Email mapper
Name: email
Mapper Type: Attribute Importer
Attribute Name: http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress
User Attribute Name: email
Username mapper
Name: username
Mapper Type: Attribute Importer
Attribute Name: http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name
User Attribute Name: username
First Name mapper
Name: firstName
Mapper Type: Attribute Importer
Attribute Name: http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname
User Attribute Name: firstName
Last Name mapper
Name: lastName
Mapper Type: Attribute Importer
Attribute Name: http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname
User Attribute Name: lastName
Groups mapper
Name: groups
Mapper Type: Attribute Importer
Attribute Name: http://schemas.microsoft.com/ws/2008/06/identity/claims/groups
User Attribute Name: groups
Configure SSL certificates
Set up SSL certificates for secure SAML communication. SAML requires proper certificate configuration for signature validation.
# Generate self-signed certificate for testing
sudo openssl req -newkey rsa:2048 -nodes -keyout /opt/keycloak/conf/keycloak.key -x509 -days 365 -out /opt/keycloak/conf/keycloak.crt -subj "/CN=your.keycloak.domain.com"
Convert to PKCS12 format
sudo openssl pkcs12 -export -in /opt/keycloak/conf/keycloak.crt -inkey /opt/keycloak/conf/keycloak.key -out /opt/keycloak/conf/keycloak.p12 -name keycloak -passout pass:keystore_password
Set proper permissions
sudo chown keycloak:keycloak /opt/keycloak/conf/keycloak.*
Update Keycloak configuration for HTTPS
Configure HTTPS and certificate settings in the Keycloak configuration file.
# Add HTTPS configuration
https-certificate-file=/opt/keycloak/conf/keycloak.crt
https-certificate-key-file=/opt/keycloak/conf/keycloak.key
Optional: HTTPS keystore configuration
https-key-store-file=/opt/keycloak/conf/keycloak.p12
https-key-store-password=keystore_password
https-key-store-type=PKCS12
Configure reverse proxy for production
Set up NGINX as a reverse proxy for Keycloak with proper headers and SSL termination.
server {
listen 80;
server_name your.keycloak.domain.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name your.keycloak.domain.com;
ssl_certificate /path/to/your/certificate.crt;
ssl_certificate_key /path/to/your/private.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384;
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:50m;
ssl_stapling on;
ssl_stapling_verify on;
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_set_header X-Forwarded-Port $server_port;
proxy_buffer_size 128k;
proxy_buffers 4 256k;
proxy_busy_buffers_size 256k;
proxy_connect_timeout 30s;
proxy_send_timeout 30s;
proxy_read_timeout 30s;
}
}
Enable and restart services
Enable NGINX site configuration and restart both services to apply the changes.
sudo ln -s /etc/nginx/sites-available/keycloak /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl restart nginx
sudo systemctl restart keycloak
Configure user federation
Set up user federation to import users from LDAP or Active Directory with automatic synchronization.
# In Keycloak Admin Console: User Federation -> Add Provider -> ldap
Connection Settings
Console Display Name: Active Directory
Vendor: Active Directory
Connection URL: ldap://your-ad-server:389
Bind Type: simple
Bind DN: CN=keycloak-service,OU=Service Accounts,DC=example,DC=com
Bind Credential: service_account_password
LDAP Searching and Updating
Users DN: OU=Users,DC=example,DC=com
Username LDAP attribute: sAMAccountName
RDN LDAP attribute: cn
UUID LDAP attribute: objectGUID
User Object Classes: person, organizationalPerson, user
Synchronization Settings
Import Users: ON
Edit Mode: READ_ONLY
Sync Registrations: OFF
Periodic Full Sync: ON
Full Sync Period: 86400
Periodic Changed Users Sync: ON
Changed Users Sync Period: 3600
Verify your setup
Test the SAML integration and verify all components are working correctly.
# Check Keycloak service status
sudo systemctl status keycloak
Verify database connection
sudo -u postgres psql -c "\c keycloak; SELECT COUNT(*) FROM public.realm;"
Test SAML metadata endpoint
curl -k https://your.keycloak.domain.com/realms/your-realm/protocol/saml/descriptor
Check NGINX configuration
sudo nginx -t
Monitor Keycloak logs
sudo tail -f /opt/keycloak/data/log/keycloak.log
Access the Keycloak admin console at https://your.keycloak.domain.com and test the SAML flow by initiating SSO from a configured service provider.
Common issues
| Symptom | Cause | Fix |
|---|---|---|
| SAML signature validation fails | Clock skew or certificate issues | Sync system clocks with NTP and verify certificate validity |
| Attribute mapping not working | Incorrect SAML attribute names | Check IdP metadata for exact attribute names and case sensitivity |
| User federation sync fails | LDAP connection or permission issues | Test LDAP connection manually and verify service account permissions |
| Keycloak won't start | Database connection or memory issues | Check PostgreSQL status and increase JVM heap size in systemd service |
| SSL handshake failures | Certificate chain or cipher issues | Verify complete certificate chain and update SSL configuration |
Next steps
- Configure Keycloak OAuth2 integration with web applications using OIDC and JWT tokens
- Set up Grafana Enterprise SSO authentication with LDAP, SAML, and OAuth2 integration
- Configure Keycloak high availability clustering for production environments
- Setup Keycloak user federation with multiple LDAP providers and attribute mapping
- Configure Keycloak custom authentication flows with MFA and conditional policies
Running this in production?
Automated install script
Run this to automate the entire setup
#!/usr/bin/env bash
set -euo pipefail
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
# Usage function
usage() {
echo "Usage: $0 <hostname> [database_password]"
echo "Example: $0 keycloak.example.com mySecurePassword123"
exit 1
}
# Error handling
cleanup() {
echo -e "${RED}Error occurred during installation. Cleaning up...${NC}"
systemctl stop keycloak 2>/dev/null || true
systemctl disable keycloak 2>/dev/null || true
rm -f /etc/systemd/system/keycloak.service
userdel -r keycloak 2>/dev/null || true
rm -rf /opt/keycloak
}
trap cleanup ERR
# Check arguments
if [ $# -lt 1 ] || [ $# -gt 2 ]; then
usage
fi
HOSTNAME="$1"
DB_PASSWORD="${2:-$(openssl rand -base64 32 | tr -d '=+/')}"
ADMIN_PASSWORD="$(openssl rand -base64 32 | tr -d '=+/')"
# Check if running as root
if [ "$EUID" -ne 0 ]; then
echo -e "${RED}Please run as root or with sudo${NC}"
exit 1
fi
echo -e "${GREEN}Starting Keycloak SAML installation for hostname: $HOSTNAME${NC}"
# Auto-detect distribution
echo -e "${YELLOW}[1/10] Detecting operating system...${NC}"
if [ -f /etc/os-release ]; then
. /etc/os-release
case "$ID" in
ubuntu|debian)
PKG_MGR="apt"
PKG_INSTALL="apt install -y"
PKG_UPDATE="apt update"
POSTGRES_SERVICE="postgresql"
POSTGRES_INITDB=""
;;
almalinux|rocky|centos|rhel|ol)
PKG_MGR="dnf"
PKG_INSTALL="dnf install -y"
PKG_UPDATE="dnf update -y"
POSTGRES_SERVICE="postgresql"
POSTGRES_INITDB="postgresql-setup --initdb"
;;
fedora)
PKG_MGR="dnf"
PKG_INSTALL="dnf install -y"
PKG_UPDATE="dnf update -y"
POSTGRES_SERVICE="postgresql"
POSTGRES_INITDB="postgresql-setup --initdb"
;;
amzn)
PKG_MGR="yum"
PKG_INSTALL="yum install -y"
PKG_UPDATE="yum update -y"
POSTGRES_SERVICE="postgresql"
POSTGRES_INITDB="postgresql-setup initdb"
;;
*)
echo -e "${RED}Unsupported distribution: $ID${NC}"
exit 1
;;
esac
echo -e "${GREEN}Detected: $PRETTY_NAME${NC}"
else
echo -e "${RED}Cannot detect operating system${NC}"
exit 1
fi
# Update system
echo -e "${YELLOW}[2/10] Updating system packages...${NC}"
$PKG_UPDATE
# Install dependencies
echo -e "${YELLOW}[3/10] Installing dependencies...${NC}"
case "$ID" in
ubuntu|debian)
$PKG_INSTALL openjdk-17-jdk wget postgresql postgresql-contrib openssl
;;
*)
$PKG_INSTALL java-17-openjdk wget postgresql postgresql-server postgresql-contrib openssl
;;
esac
# Initialize and start PostgreSQL
echo -e "${YELLOW}[4/10] Configuring PostgreSQL...${NC}"
if [ -n "$POSTGRES_INITDB" ]; then
$POSTGRES_INITDB 2>/dev/null || true
fi
systemctl enable $POSTGRES_SERVICE
systemctl start $POSTGRES_SERVICE
# Create keycloak user
echo -e "${YELLOW}[5/10] Creating keycloak user...${NC}"
if ! id keycloak &>/dev/null; then
useradd -r -s /bin/false keycloak
fi
# Download and install Keycloak
echo -e "${YELLOW}[6/10] Downloading and installing Keycloak...${NC}"
cd /opt
if [ ! -d "/opt/keycloak" ]; then
wget -q https://github.com/keycloak/keycloak/releases/download/23.0.3/keycloak-23.0.3.tar.gz
tar -xzf keycloak-23.0.3.tar.gz
mv keycloak-23.0.3 keycloak
rm keycloak-23.0.3.tar.gz
fi
chown -R keycloak:keycloak /opt/keycloak
# Create data and log directories
mkdir -p /opt/keycloak/data/log
chown -R keycloak:keycloak /opt/keycloak/data
# Configure database
echo -e "${YELLOW}[7/10] Setting up database...${NC}"
sudo -u postgres psql -c "CREATE DATABASE keycloak;" 2>/dev/null || true
sudo -u postgres psql -c "CREATE USER keycloak WITH PASSWORD '$DB_PASSWORD';" 2>/dev/null || true
sudo -u postgres psql -c "GRANT ALL PRIVILEGES ON DATABASE keycloak TO keycloak;"
# Create Keycloak configuration
echo -e "${YELLOW}[8/10] Creating Keycloak configuration...${NC}"
cat > /opt/keycloak/conf/keycloak.conf << EOF
# Database configuration
db=postgres
db-url=jdbc:postgresql://localhost/keycloak
db-username=keycloak
db-password=$DB_PASSWORD
# Hostname configuration
hostname=$HOSTNAME
hostname-strict=false
# HTTP/HTTPS configuration
http-enabled=true
http-port=8080
https-port=8443
# Proxy configuration
proxy=edge
# Logging
log-level=INFO
log-file=/opt/keycloak/data/log/keycloak.log
EOF
chown keycloak:keycloak /opt/keycloak/conf/keycloak.conf
chmod 640 /opt/keycloak/conf/keycloak.conf
# Create systemd service
echo -e "${YELLOW}[9/10] Creating systemd service...${NC}"
cat > /etc/systemd/system/keycloak.service << EOF
[Unit]
Description=Keycloak Identity and Access Management
After=network.target postgresql.service
Requires=postgresql.service
[Service]
Type=notify
User=keycloak
Group=keycloak
WorkingDirectory=/opt/keycloak
ExecStart=/opt/keycloak/bin/kc.sh start
Restart=always
RestartSec=30
TimeoutStartSec=300
TimeoutStopSec=30
# Resource limits
LimitNOFILE=65536
LimitNPROC=4096
# Environment variables
Environment=KEYCLOAK_ADMIN=admin
Environment=KEYCLOAK_ADMIN_PASSWORD=$ADMIN_PASSWORD
Environment=JAVA_OPTS=-Xms2g -Xmx4g -XX:MetaspaceSize=96M -XX:MaxMetaspaceSize=256m
[Install]
WantedBy=multi-user.target
EOF
# Build and start Keycloak
echo -e "${YELLOW}[10/10] Building and starting Keycloak...${NC}"
sudo -u keycloak /opt/keycloak/bin/kc.sh build
systemctl daemon-reload
systemctl enable keycloak
systemctl start keycloak
# Configure firewall
if command -v firewall-cmd &> /dev/null; then
firewall-cmd --permanent --add-port=8080/tcp
firewall-cmd --reload
elif command -v ufw &> /dev/null; then
ufw allow 8080/tcp
fi
# Wait for Keycloak to start
echo -e "${YELLOW}Waiting for Keycloak to start...${NC}"
sleep 30
# Verify installation
echo -e "${YELLOW}Verifying installation...${NC}"
if systemctl is-active --quiet keycloak; then
echo -e "${GREEN}✓ Keycloak service is running${NC}"
else
echo -e "${RED}✗ Keycloak service failed to start${NC}"
systemctl status keycloak
exit 1
fi
if curl -sf http://localhost:8080 > /dev/null; then
echo -e "${GREEN}✓ Keycloak is responding on port 8080${NC}"
else
echo -e "${RED}✗ Keycloak is not responding${NC}"
exit 1
fi
echo -e "${GREEN}Keycloak installation completed successfully!${NC}"
echo
echo -e "${YELLOW}Access Information:${NC}"
echo "URL: http://$HOSTNAME:8080"
echo "Admin Username: admin"
echo "Admin Password: $ADMIN_PASSWORD"
echo "Database Password: $DB_PASSWORD"
echo
echo -e "${YELLOW}Next Steps:${NC}"
echo "1. Access the admin console at http://$HOSTNAME:8080"
echo "2. Create a new realm for your applications"
echo "3. Configure SAML clients for your applications"
echo "4. Set up SSL/TLS with a reverse proxy for production use"
echo
echo -e "${RED}IMPORTANT: Save the admin password shown above!${NC}"
Review the script before running. Execute with: bash install.sh