diff --git a/docbook/reference/en/en-US/master.xml b/docbook/reference/en/en-US/master.xml
index 751436c4c2..c0d39db27e 100755
--- a/docbook/reference/en/en-US/master.xml
+++ b/docbook/reference/en/en-US/master.xml
@@ -34,6 +34,7 @@
+
]>
@@ -125,6 +126,7 @@ This one is short
&SAML;
&SecurityVulnerabilities;
&Clustering;
+ &ApplicationClustering;
&Migration;
diff --git a/docbook/reference/en/en-US/modules/adapter-config.xml b/docbook/reference/en/en-US/modules/adapter-config.xml
index 8f66847fb4..14c8f293a3 100755
--- a/docbook/reference/en/en-US/modules/adapter-config.xml
+++ b/docbook/reference/en/en-US/modules/adapter-config.xml
@@ -291,6 +291,51 @@
+
+ auth-server-url-for-backend-requests
+
+
+ Alternative location of auth-server-url used just for backend requests. It must be absolute URI. Useful
+ especially in cluster (see Relative URI Optimization) or if you would like to use https for browser requests
+ but stick with http for backend requests etc.
+
+
+
+
+ always-refresh-token
+
+
+ If true, Keycloak will refresh token in every request. More info in Refresh token in each request .
+
+
+
+
+ register-node-at-startup
+
+
+ If true, then adapter will send registration request to Keycloak. It's false
+ by default as useful just in cluster (See Registration of application nodes to Keycloak)
+
+
+
+
+ register-node-period
+
+
+ Period for re-registration adapter to Keycloak. Useful in cluster. See Registration of application nodes to Keycloak for details.
+
+
+
+
+ token-store
+
+
+ Possible values are session and cookie. Default is session,
+ which means that adapter stores account info in HTTP Session. Alternative cookie means storage of info in cookie.
+ See Stateless token store for details.
+
+
+
diff --git a/docbook/reference/en/en-US/modules/application-clustering.xml b/docbook/reference/en/en-US/modules/application-clustering.xml
new file mode 100644
index 0000000000..1531d1e4b9
--- /dev/null
+++ b/docbook/reference/en/en-US/modules/application-clustering.xml
@@ -0,0 +1,254 @@
+
+ Application Clustering
+
+ This 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.
+
+
+
+ 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 disadvantage 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.
+
+
+
+
+ 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/myapp .
+
+
+ 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 send 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.
+
+
+
\ No newline at end of file
diff --git a/docbook/reference/en/en-US/modules/timeouts.xml b/docbook/reference/en/en-US/modules/timeouts.xml
index e5f4e82049..62d72a6ade 100755
--- a/docbook/reference/en/en-US/modules/timeouts.xml
+++ b/docbook/reference/en/en-US/modules/timeouts.xml
@@ -33,7 +33,7 @@
in that it allow you to force a relogin after a set timeframe.
-
+ Token Timeouts
The Access Token Lifespan is how long an access token is valid for. An access token contains everything
diff --git a/integration/adapter-core/src/main/java/org/keycloak/adapters/AdapterTokenStore.java b/integration/adapter-core/src/main/java/org/keycloak/adapters/AdapterTokenStore.java
index fd2c5c3221..0d3be9621a 100644
--- a/integration/adapter-core/src/main/java/org/keycloak/adapters/AdapterTokenStore.java
+++ b/integration/adapter-core/src/main/java/org/keycloak/adapters/AdapterTokenStore.java
@@ -1,7 +1,5 @@
package org.keycloak.adapters;
-import org.keycloak.KeycloakSecurityContext;
-
/**
* Abstraction for storing token info on adapter side. Intended to be per-request object
*
diff --git a/integration/adapter-core/src/main/java/org/keycloak/adapters/RefreshableKeycloakSecurityContext.java b/integration/adapter-core/src/main/java/org/keycloak/adapters/RefreshableKeycloakSecurityContext.java
index 3cd87cb455..24ac81445e 100755
--- a/integration/adapter-core/src/main/java/org/keycloak/adapters/RefreshableKeycloakSecurityContext.java
+++ b/integration/adapter-core/src/main/java/org/keycloak/adapters/RefreshableKeycloakSecurityContext.java
@@ -4,7 +4,6 @@ import org.jboss.logging.Logger;
import org.keycloak.KeycloakSecurityContext;
import org.keycloak.RSATokenVerifier;
import org.keycloak.VerificationException;
-import org.keycloak.enums.TokenStore;
import org.keycloak.representations.AccessToken;
import org.keycloak.representations.AccessTokenResponse;
import org.keycloak.representations.IDToken;
@@ -118,11 +117,4 @@ public class RefreshableKeycloakSecurityContext extends KeycloakSecurityContext
tokenStore.refreshCallback(this);
return true;
}
-
-
- protected void updateTokenCookie(KeycloakDeployment deployment, HttpFacade facade) {
- if (deployment.getTokenStore() == TokenStore.COOKIE) {
- CookieTokenStore.setTokenCookie(deployment, facade, this);
- }
- }
}
diff --git a/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/CatalinaCookieTokenStore.java b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/CatalinaCookieTokenStore.java
index 409f9c2c38..26fd307826 100644
--- a/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/CatalinaCookieTokenStore.java
+++ b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/CatalinaCookieTokenStore.java
@@ -17,7 +17,7 @@ import org.keycloak.adapters.RefreshableKeycloakSecurityContext;
import org.keycloak.adapters.RequestAuthenticator;
/**
- * per-request object
+ * Handle storage of token info in cookie. Per-request object.
*
* @author Marek Posolda
*/
diff --git a/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/CatalinaSessionTokenStore.java b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/CatalinaSessionTokenStore.java
index 08b83adf67..6fe8c5999e 100644
--- a/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/CatalinaSessionTokenStore.java
+++ b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/CatalinaSessionTokenStore.java
@@ -14,7 +14,7 @@ import org.keycloak.adapters.RefreshableKeycloakSecurityContext;
import org.keycloak.adapters.RequestAuthenticator;
/**
- * per-request object
+ * Handle storage of token info in HTTP Session. Per-request object
*
* @author Marek Posolda
*/
diff --git a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/ServletSessionTokenStore.java b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/ServletSessionTokenStore.java
index cbc7a0bcfe..fe0c6c9a98 100644
--- a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/ServletSessionTokenStore.java
+++ b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/ServletSessionTokenStore.java
@@ -15,7 +15,7 @@ import org.keycloak.adapters.RefreshableKeycloakSecurityContext;
import org.keycloak.adapters.RequestAuthenticator;
/**
- * Per-request object. Storage of tokens in servlet session.
+ * Per-request object. Storage of tokens in servlet HTTP session.
*
* @author Marek Posolda
*/