Application ClusteringThis chapter is focused on clustering support for your own AS7, EAP6 or Wildfly applications, which are secured by Keycloak.
We support various deployment scenarios according if your application is:
stateless or stateful
distributable (replicated http session) or non-distributable and just relying on sticky sessions provided by loadbalancer
deployed on same or different cluster hosts where keycloak servers are deployed
The situation is a bit tricky as application communicates with Keycloak directly within user's browser (for example redirecting to login screen),
but there is also backend (out-of-bound) communication between keycloak and application, which is hidden from end-user
and his browser and hence can't rely on sticky sessions.
To enable distributable (replicated) HTTP Sessions in your application, you may need to do some additional steps. Usually you need to put ]]>
tag into WEB-INF/web.xml file of your application and possibly do some additional steps to configure underlying cluster cache (In case of
Wildfly, the implementation of cluster cache is based on Infinispan). These steps are server specific, so consult documentation of your application server for more details.
Stateless token store
By default, the servlet web application secured by Keycloak uses HTTP session to store information about authenticated
user account. This means that this info could be replicated across cluster and your application will safely survive
failover of some cluster node.
However if you don't need or don't want to use HTTP Session, you may alternatively save all info about authenticated
account into cookie. This is useful especially if your application is:
stateless application without need of HTTP Session, but with requirement to be safe to failover of some cluster node
stateful application, but you don't want sensitive token data to be saved in HTTP session
stateless application relying on loadbalancer, which is not aware of sticky sessions (in this case cookie is your only way)
To configure this, you can add this line to configuration of your adapter in WEB-INF/keycloak.json of your application:
Default value of token-store is session, hence saving data in HTTP session.
One limitation of cookie store is, that whole info about account is passed in cookie KEYCLOAK_ADAPTER_STATE in each HTTP request.
Hence it's not the best for network performance.
Another small limitation is limited support for Single-Sign out. It works without issues if you init servlet logout (HttpServletRequest.logout)
from this application itself as the adapter will delete the KEYCLOAK_ADAPTER_STATE cookie. But back-channel logout initialized from different application can't be
propagated by Keycloak to this application with cookie store. Hence it's recommended to use very short value of access token
timeout (1 minute for example).
Relative URI optimization
In many deployment scenarios will be Keycloak and secured applications deployed on same cluster hosts. For this case Keycloak
already provides option to use relative URI as value of option auth-server-url in WEB-INF/keycloak.json .
In this case, the URI of Keycloak server is resolved from the URI of current request.
For example if your loadbalancer is on https://loadbalancer.com/myapp and auth-server-url is /auth,
then relative URI of Keycloak is resolved to be https://loadbalancer.com/auth .
For cluster setup, it may be even better to use option auth-server-url-for-backend-request . This allows to configure
that backend requests between Keycloak and your application will be sent directly to same cluster host without additional
round-trip through loadbalancer. So for this, it's good to configure values in WEB-INF/keycloak.json like this:
This would mean that browser requests (like redirecting to Keycloak login screen) will be still resolved relatively
to current request URI like https://loadbalancer.com/myapp, but backend (out-of-bound) requests between keycloak
and your app are sent always to same cluster host with application .
Note that additionally to network optimization,
you may not need "https" in this case as application and keycloak are communicating directly within same cluster host.
Admin URL configuration
Admin URL for particular application can be configured in Keycloak admin console. It's used by Keycloak server to
send backend requests to application for various tasks, like logout users or push revocation policies.
For example logout of user from Keycloak works like this:
User sends logout request from one of applications where he is logged.
Then application will send logout request to Keycloak
Keycloak server logout user in itself, and then it re-sends logout request by backend channel to all
applications where user is logged. Keycloak is using admin URL for this. So logout is propagated to all apps.
You may again use relative values for admin URL, but in cluster it may not be the best similarly like in previous section .
Some examples of possible values of admin URL are:
http://${jboss.host.name}:8080/myapp
This is best choice if "myapp" is deployed on same cluster hosts like Keycloak and is distributable.
In this case Keycloak server sends logout request to itself, hence no communication with loadbalancer
or other cluster nodes and no additional network traffic.
Note that since the application is distributable,
the backend request sent by Keycloak could be served on any application cluster node as invalidation
of HTTP Session on node1 will propagate the invalidation to other cluster nodes due to replicated HTTP sessions.
http://${application.session.host}:8080/myapp
Keycloak will track hosts where is particular HTTP Session served and it will send session
invalidation message to proper cluster node.
For example application is deployed on http://node1:8080/myapp and http://node2:8080/myapp .
Now HTTP Session session1 is sticky-session served on cluster node node2 .
When keycloak invalidates this session, it will send request directly to http://node2:8080/myapp .
This is ideal configuration for distributable applications deployed on different host than keycloak
or for non-distributable applications deployed either on same or different nodes than keycloak.
Good thing is that it doesn't send requests through load-balancer and hence helps to reduce network traffic.
Registration of application nodes to Keycloak
Previous section describes how can Keycloak send logout request to proper application node. However in some cases admin
may want to propagate admin tasks to all registered cluster nodes, not just one of them. For example push new notBefore
for realm or application, or logout all users from all applications on all cluster nodes.
In this case Keycloak should
be aware of all application cluster nodes, so it could send event to all of them. To achieve this, we support auto-discovery mechanism:
Once new application node joins cluster, it sends registration request to Keycloak server
The request may be re-sent to Keycloak in configured periodic intervals
If Keycloak won't receive re-registration request within specified timeout (should be greater than period from point 2)
then it automatically unregister particular node
Node is also unregistered in Keycloak when it sends unregistration request, which is usually during node
shutdown or application undeployment. This may not work properly for forced shutdown when
undeployment listeners are not invoked, so here you need to rely on automatic unregistration from point 3 .
Sending startup registrations and periodic re-registration is disabled by default, as it's main usecase is just
cluster deployment. In WEB-INF/keycloak.json of your application, you can specify:
which means that registration is sent at startup (accurately when 1st request is served by the application node)
and then it's resent each 10 minutes.
In Keycloak admin console you can specify the maximum node re-registration timeout (makes sense to have it
bigger than register-node-period from adapter configuration for particular application). Also you
can manually add and remove cluster nodes in admin console, which is useful if you don't want to rely on adapter's
automatic registration or if you want to remove stale application nodes, which weren't unregistered
(for example due to forced shutdown).
Refresh token in each request
By default, application adapter tries to refresh access token when it's expired (period can be specified as Access Token Lifespan) .
However if you don't want to rely on the fact, that Keycloak is able to successfully propagate admin events like logout
to your application nodes, then you have possibility to configure adapter to refresh access token in each HTTP request.
In WEB-INF/keycloak.json you can configure:
Note that this has big performance impact. It's useful just if performance is not priority, but security is critical
and you can't rely on logout and push notBefore propagation from Keycloak to applications.