Skip to content

Last updated: 2026-06-25

Keycloak TLS/SSL Configuration Guide

This guide provides recommended TLS/SSL settings for Keycloak, the open-source identity and access management server. Keycloak issues tokens and handles credentials, so every connection to it must be encrypted: an attacker who can read Keycloak traffic can capture passwords, authorization codes, and access tokens. The current Keycloak distribution is built on Quarkus and is configured through kc.sh flags or the keycloak.conf file.

Prerequisites

  • Keycloak 26 or later (Quarkus distribution)
  • Java 17 or later (Java 21 recommended)
  • A valid SSL/TLS certificate

Certificate Setup

Keycloak accepts PEM certificate and key files directly, or a Java keystore. PEM is simplest:

chmod 640 /etc/keycloak/ssl/privkey.pem
chown keycloak:keycloak /etc/keycloak/ssl/privkey.pem
chmod 644 /etc/keycloak/ssl/fullchain.pem

Enabling TLS

Point Keycloak at the certificate and key. These can be passed as kc.sh flags or set in conf/keycloak.conf (drop the leading -- for the file form).

bin/kc.sh start \
    --https-certificate-file=/etc/keycloak/ssl/fullchain.pem \
    --https-certificate-key-file=/etc/keycloak/ssl/privkey.pem

Keycloak reloads the certificate and key every hour by default, so certificates can be rotated on disk without restarting the server.

Keystore Alternative

To use a Java keystore (PKCS12) instead of PEM files:

bin/kc.sh start \
    --https-key-store-file=/etc/keycloak/ssl/keystore.p12 \
    --https-key-store-password=changeit \
    --https-key-store-type=PKCS12

Force HTTPS Only

Disable the plaintext HTTP listener so clients can only connect over TLS, and require a hostname:

http-enabled=false
hostname=https://sso.example.com

Protocol Versions

Restrict Keycloak to TLS 1.2 and TLS 1.3:

https-protocols=TLSv1.3,TLSv1.2

Cipher Suites

Keycloak uses Java (JSSE) cipher suite names. Restrict the TLS 1.2 suites to AEAD ciphers with ECDHE key exchange. TLS 1.3 suites are managed by the JVM and are always secure.

https-cipher-suites=TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256

Note: The ChaCha20-Poly1305 suites require Java 12 or later. Keycloak 26 requires Java 17, so they are always available; on a hypothetical older JDK, omit the two ChaCha20 entries.

Mutual TLS

To require clients to present a certificate (for example, for service-to-service authentication or x509 browser login), set the client-auth mode:

https-client-auth=required

Available values: none (default), request (validate a certificate if presented, but do not require one), and required (always require a valid client certificate). Combine request or required with a truststore so Keycloak can verify the client chain:

https-trust-store-file=/etc/keycloak/ssl/client-ca.p12
https-trust-store-password=changeit

See RFC 8446 ยง4.3.2 for the TLS Certificate Request specification, and Wikipedia: Mutual authentication for a general overview.

Reverse Proxy

Keycloak is frequently deployed behind a reverse proxy or load balancer that terminates TLS (see the nginx, HAProxy, or Apache guides for the proxy side). When it is, tell Keycloak to trust the forwarded headers so it builds correct token issuer URLs and redirect URIs:

proxy-headers=xforwarded

Use xforwarded for the X-Forwarded-* headers or forwarded for the standard RFC 7239 Forwarded header, matching what your proxy sends. Only enable this behind a trusted proxy, since these headers are otherwise client-controlled.

For end-to-end encryption, keep TLS enabled on Keycloak itself (re-encryption) rather than terminating at the proxy and forwarding plaintext. Terminating at the proxy is acceptable only when the proxy-to-Keycloak hop is on a trusted network segment.

Complete Configuration

A complete conf/keycloak.conf:

# Network
hostname=https://sso.example.com
https-port=8443
http-enabled=false

# Certificate (PEM)
https-certificate-file=/etc/keycloak/ssl/fullchain.pem
https-certificate-key-file=/etc/keycloak/ssl/privkey.pem

# Protocols and ciphers
https-protocols=TLSv1.3,TLSv1.2
https-cipher-suites=TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256

# Database (example)
db=postgres
db-url=jdbc:postgresql://localhost/keycloak

By default Keycloak binds the HTTPS listener on all interfaces (IPv4 and IPv6). To restrict it, set https-host to a specific address.

After changing build-time options, run bin/kc.sh build before start; the TLS options above are runtime options and take effect on start alone.

Security Notes

Keycloak uses Java's JSSE (Java Secure Socket Extension) for TLS. Vulnerability fixes are tied to the JDK version in use, and Keycloak 26 requires Java 17 or later, so all of the defaults below are satisfied:

  • POODLE (CVE-2014-3566, 2014): SSL 3.0 disabled by default since Java 8u31 (January 2015); excluded from the recommended configuration.
  • BEAST (CVE-2011-3389, 2011): TLS 1.0 disabled by default since Java 8u292 / Java 11.0.11 (April 2021); excluded by the TLS 1.2 minimum.
  • FREAK (CVE-2015-0204, 2015): EXPORT ciphers disabled by default since Java 8u40 (March 2015).
  • Sweet32 (CVE-2016-2183, 2016): 3DES disabled by default since Java 8u151 (October 2017); excluded from the recommended cipher list.
  • ROBOT (2017): Static RSA key exchange is excluded from the recommended configuration.
  • LOGJAM (CVE-2015-4000, 2015): DHE with weak keys excluded; only ECDHE is recommended.
  • Downgrade attacks: TLS_FALLBACK_SCSV supported since Java 8u31.

The following are not addressable through TLS configuration alone:

  • Heartbleed (CVE-2014-0160, 2014): Not applicable. Java's JSSE is an independent TLS implementation not based on OpenSSL and was never affected by Heartbleed.
  • BREACH (CVE-2013-3587, 2013): Keycloak serves HTTP responses; if response compression is enabled at Keycloak or a fronting proxy, apply BREACH countermeasures at that layer. TLS configuration cannot prevent it.
  • DROWN (CVE-2016-0800, 2016): Not applicable. Java's JSSE does not support SSLv2.

Verification

Start Keycloak:

bin/kc.sh start

Test the TLS connection and protocol negotiation:

openssl s_client -connect sso.example.com:8443

Confirm the health endpoint responds over HTTPS:

curl --cacert /etc/keycloak/ssl/ca.pem https://sso.example.com:8443/health/ready

Audit the negotiated protocols and ciphers with Qualys SSL Labs or testssl.sh.


Related Guides

View all Infrastructure guides →

Configured TLS? Now Monitor It.

Generator Labs alerts you before certificates expire, get revoked, or fail chain validation, across HTTPS, SMTPS, IMAPS, LDAPS, and more.

Certificate Monitoring →