Keycloak’s default HTTP configuration is a security liability, and forcing it to use TLS with valid certificates is non-negotiable for production.

Let’s see Keycloak in action, serving requests over HTTPS. Imagine a user trying to log in to an application secured by Keycloak. Their browser initiates a TLS handshake with the Keycloak server on port 8443 (the default HTTPS port). The browser receives Keycloak’s certificate, verifies its authenticity against trusted Certificate Authorities (CAs), and if valid, proceeds with the encrypted communication. The application then redirects the user to Keycloak’s login page, all traffic between the browser and Keycloak is encrypted. After successful authentication, Keycloak redirects the user back to the application with an authentication token, also transmitted securely.

Keycloak handles TLS termination internally. This means Keycloak itself is responsible for decrypting incoming HTTPS requests and encrypting outgoing responses. It uses the Java KeyStore (JKS) or PKCS12 format to store its private key and the corresponding certificate chain. When a client (like a user’s browser or another service) connects, Keycloak presents its configured certificate and uses its private key to establish the secure TLS connection.

The primary problem Keycloak solves with TLS is protecting sensitive authentication data (usernames, passwords, tokens) from eavesdropping as it traverses the network. Without TLS, this data would be sent in plaintext, making it trivial for an attacker on the same network to intercept and steal credentials.

Here’s a breakdown of the configuration levers you pull:

  • KeyStore File: This is the container for your certificate and private key. It can be in JKS or PKCS12 format.
  • KeyStore Password: The password to unlock the KeyStore file.
  • Key Alias: The specific name within the KeyStore that identifies your server’s certificate and private key.
  • Key Password: The password for the private key itself (often the same as the KeyStore password, but can be different).
  • HTTPS Port: The port Keycloak will listen on for HTTPS connections. The default is 8443.
  • Certificate Chain: This includes your server certificate and any intermediate certificates that link it back to a trusted root CA.

Here’s how you’d typically configure this using the standalone.xml or domain.xml configuration file. You’ll need to modify the http-listener or https-listener section.

<subsystem xmlns="urn:jboss:domain:undertow:10.0">
    <buffer-cache name="default"/>
    <server name="default-server">
        <http-listener name="default" socket-binding="http"/>
        <https-listener name="https" socket-binding="https" security-realm="ApplicationRealm"/>
    </server>
    <servlet-container name="default-servlet-container">
        <jsp-configuration/>
    </servlet-container>
    <host name="default-host" alias="localhost">
        <location name="/" handler="welcome-content"/>
        <filter-ref name="server-header"/>
        <filter-ref name="x-powered-by-header"/>
    </host>
</subsystem>
...
<socket-binding-group name="standard-sockets" default-interface="public">
    <socket-binding name="http" port="8080"/>
    <socket-binding name="https" port="8443"/>
    ...
</socket-binding-group>
...
<security-realms>
    <security-realm name="ApplicationRealm">
        <server-identities>
            <ssl>
                <keystore path="path/to/your/keystore.jks"
                          keystore-password="your_keystore_password"
                          alias="your_key_alias"
                          key-password="your_key_password"/>
            </ssl>
        </server-identities>
        <authentication>
            <local name="local" allowed-users="*" realms="ExternalRealm"/>
            <identity-login name="identity"/>
        </authentication>
    </security-realm>
</security-realms>

Make sure the path/to/your/keystore.jks is accessible by the Keycloak process. The keystore-password, alias, and key-password must precisely match what’s in your keystore.

The most surprising thing about Keycloak’s TLS configuration is that it doesn’t automatically enforce certificate validation for its own internal clients (like the admin console or other Keycloak services if you’re in a clustered environment). While it handles TLS termination for external clients using your valid certificate, the internal trust mechanisms can sometimes rely on simpler configurations if not explicitly hardened.

If you’ve set up your Keycloak instance to use HTTPS, you might then encounter issues with clients unable to reach the admin console or other services, often manifesting as connection refused errors on the HTTPS port.

Want structured learning?

Take the full Keycloak course →