keycloak-aplcache

Changes

core/src/main/java/org/keycloak/representations/adapters/action/SessionStats.java 37(+0 -37)

core/src/main/java/org/keycloak/representations/adapters/action/SessionStatsAction.java 35(+0 -35)

core/src/main/java/org/keycloak/representations/adapters/action/UserStatsAction.java 31(+0 -31)

Details

diff --git a/core/src/main/java/org/keycloak/adapters/AdapterConstants.java b/core/src/main/java/org/keycloak/adapters/AdapterConstants.java
index 6ad29c7..988bfba 100755
--- a/core/src/main/java/org/keycloak/adapters/AdapterConstants.java
+++ b/core/src/main/java/org/keycloak/adapters/AdapterConstants.java
@@ -18,4 +18,7 @@ public interface AdapterConstants {
     // org.keycloak.subsystem.extensionKeycloakAdapterConfigDeploymentProcessor.  We have this value in
     // two places to avoid dependency between Keycloak Subsystem and Keyclaok Undertow Integration.
     String AUTH_DATA_PARAM_NAME = "org.keycloak.json.adapterConfig";
+
+    // Attribute passed in codeToToken request from adapter to Keycloak and saved in ClientSession.
+    public static final String HTTP_SESSION_ID = "http_session_id";
 }
diff --git a/core/src/main/java/org/keycloak/representations/adapters/action/LogoutAction.java b/core/src/main/java/org/keycloak/representations/adapters/action/LogoutAction.java
index b89b10d..a14b3f8 100755
--- a/core/src/main/java/org/keycloak/representations/adapters/action/LogoutAction.java
+++ b/core/src/main/java/org/keycloak/representations/adapters/action/LogoutAction.java
@@ -1,40 +1,25 @@
 package org.keycloak.representations.adapters.action;
 
+import java.util.List;
+
 /**
  * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
  * @version $Revision: 1 $
  */
 public class LogoutAction extends AdminAction {
     public static final String LOGOUT = "LOGOUT";
-    protected String user;
-    private String session;
+    protected List<String> adapterSessionIds;
     protected int notBefore;
 
     public LogoutAction() {
     }
 
-    public LogoutAction(String id, int expiration, String resource, String user, String session, int notBefore) {
+    public LogoutAction(String id, int expiration, String resource, List<String> adapterSessionIds, int notBefore) {
         super(id, expiration, resource, LOGOUT);
-        this.user = user;
-        this.session = session;
+        this.adapterSessionIds = adapterSessionIds;
         this.notBefore = notBefore;
     }
 
-    public String getUser() {
-        return user;
-    }
-
-    public void setUser(String user) {
-        this.user = user;
-    }
-
-    public String getSession() {
-        return session;
-    }
-
-    public void setSession(String session) {
-        this.session = session;
-    }
 
     public int getNotBefore() {
         return notBefore;
@@ -44,6 +29,10 @@ public class LogoutAction extends AdminAction {
         this.notBefore = notBefore;
     }
 
+    public List<String> getAdapterSessionIds() {
+        return adapterSessionIds;
+    }
+
     @Override
     public boolean validate() {
         return LOGOUT.equals(action);
diff --git a/core/src/main/java/org/keycloak/representations/adapters/config/AdapterConfig.java b/core/src/main/java/org/keycloak/representations/adapters/config/AdapterConfig.java
index fd54ce2..7f62fd1 100755
--- a/core/src/main/java/org/keycloak/representations/adapters/config/AdapterConfig.java
+++ b/core/src/main/java/org/keycloak/representations/adapters/config/AdapterConfig.java
@@ -17,7 +17,7 @@ import org.codehaus.jackson.annotate.JsonPropertyOrder;
         "connection-pool-size",
         "allow-any-hostname", "disable-trust-manager", "truststore", "truststore-password",
         "client-keystore", "client-keystore-password", "client-key-password",
-        "auth-server-url-for-backend-requests"
+        "auth-server-url-for-backend-requests", "always-refresh-token"
 })
 public class AdapterConfig extends BaseAdapterConfig {
 
@@ -39,6 +39,8 @@ public class AdapterConfig extends BaseAdapterConfig {
     protected int connectionPoolSize = 20;
     @JsonProperty("auth-server-url-for-backend-requests")
     protected String authServerUrlForBackendRequests;
+    @JsonProperty("always-refresh-token")
+    protected boolean alwaysRefreshToken = false;
 
     public boolean isAllowAnyHostname() {
         return allowAnyHostname;
@@ -111,4 +113,12 @@ public class AdapterConfig extends BaseAdapterConfig {
     public void setAuthServerUrlForBackendRequests(String authServerUrlForBackendRequests) {
         this.authServerUrlForBackendRequests = authServerUrlForBackendRequests;
     }
+
+    public boolean isAlwaysRefreshToken() {
+        return alwaysRefreshToken;
+    }
+
+    public void setAlwaysRefreshToken(boolean alwaysRefreshToken) {
+        this.alwaysRefreshToken = alwaysRefreshToken;
+    }
 }
diff --git a/integration/adapter-core/src/main/java/org/keycloak/adapters/AdapterDeploymentContext.java b/integration/adapter-core/src/main/java/org/keycloak/adapters/AdapterDeploymentContext.java
index f1e5292..69e61aa 100755
--- a/integration/adapter-core/src/main/java/org/keycloak/adapters/AdapterDeploymentContext.java
+++ b/integration/adapter-core/src/main/java/org/keycloak/adapters/AdapterDeploymentContext.java
@@ -326,6 +326,16 @@ public class AdapterDeploymentContext {
         public void setCorsAllowedHeaders(String corsAllowedHeaders) {
             delegate.setCorsAllowedHeaders(corsAllowedHeaders);
         }
+
+        @Override
+        public boolean isAlwaysRefreshToken() {
+            return delegate.isAlwaysRefreshToken();
+        }
+
+        @Override
+        public void setAlwaysRefreshToken(boolean alwaysRefreshToken) {
+            delegate.setAlwaysRefreshToken(alwaysRefreshToken);
+        }
     }
 
     protected KeycloakUriBuilder getBaseBuilder(HttpFacade facade, String base) {
diff --git a/integration/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeployment.java b/integration/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeployment.java
index db284b1..c376112 100755
--- a/integration/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeployment.java
+++ b/integration/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeployment.java
@@ -47,6 +47,7 @@ public class KeycloakDeployment {
     protected String corsAllowedHeaders;
     protected String corsAllowedMethods;
     protected boolean exposeToken;
+    protected boolean alwaysRefreshToken;
     protected volatile int notBefore;
 
     public KeycloakDeployment() {
@@ -281,4 +282,11 @@ public class KeycloakDeployment {
         this.notBefore = notBefore;
     }
 
+    public boolean isAlwaysRefreshToken() {
+        return alwaysRefreshToken;
+    }
+
+    public void setAlwaysRefreshToken(boolean alwaysRefreshToken) {
+        this.alwaysRefreshToken = alwaysRefreshToken;
+    }
 }
diff --git a/integration/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeploymentBuilder.java b/integration/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeploymentBuilder.java
index 5aa996b..6e5c29f 100755
--- a/integration/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeploymentBuilder.java
+++ b/integration/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeploymentBuilder.java
@@ -35,7 +35,7 @@ public class KeycloakDeploymentBuilder {
 
         String realmKeyPem = adapterConfig.getRealmKey();
         if (realmKeyPem != null) {
-            PublicKey realmKey = null;
+            PublicKey realmKey;
             try {
                 realmKey = PemUtils.decodePublicKey(realmKeyPem);
             } catch (Exception e) {
@@ -60,9 +60,7 @@ public class KeycloakDeploymentBuilder {
         }
 
         deployment.setBearerOnly(adapterConfig.isBearerOnly());
-
-        if (adapterConfig.isBearerOnly()) {
-        }
+        deployment.setAlwaysRefreshToken(adapterConfig.isAlwaysRefreshToken());
 
         if (realmKeyPem == null && adapterConfig.isBearerOnly() && adapterConfig.getAuthServerUrl() == null) {
             throw new IllegalArgumentException("For bearer auth, you must set the realm-public-key or auth-server-url");
@@ -82,7 +80,7 @@ public class KeycloakDeploymentBuilder {
     public static KeycloakDeployment build(InputStream is) {
         ObjectMapper mapper = new ObjectMapper(new SystemPropertiesJsonParserFactory());
         mapper.setSerializationInclusion(JsonSerialize.Inclusion.NON_DEFAULT);
-        AdapterConfig adapterConfig = null;
+        AdapterConfig adapterConfig;
         try {
             adapterConfig = mapper.readValue(is, AdapterConfig.class);
         } catch (IOException e) {
diff --git a/integration/adapter-core/src/main/java/org/keycloak/adapters/OAuthRequestAuthenticator.java b/integration/adapter-core/src/main/java/org/keycloak/adapters/OAuthRequestAuthenticator.java
index 3932cb0..c3c2e6e 100755
--- a/integration/adapter-core/src/main/java/org/keycloak/adapters/OAuthRequestAuthenticator.java
+++ b/integration/adapter-core/src/main/java/org/keycloak/adapters/OAuthRequestAuthenticator.java
@@ -21,6 +21,7 @@ import java.util.concurrent.atomic.AtomicLong;
 public abstract class OAuthRequestAuthenticator {
     private static final Logger log = Logger.getLogger(OAuthRequestAuthenticator.class);
     protected KeycloakDeployment deployment;
+    protected RequestAuthenticator reqAuthenticator;
     protected int sslRedirectPort;
     protected String tokenString;
     protected String idTokenString;
@@ -31,7 +32,8 @@ public abstract class OAuthRequestAuthenticator {
     protected String refreshToken;
     protected String strippedOauthParametersRequestUri;
 
-    public OAuthRequestAuthenticator(HttpFacade facade, KeycloakDeployment deployment, int sslRedirectPort) {
+    public OAuthRequestAuthenticator(RequestAuthenticator requestAuthenticator, HttpFacade facade, KeycloakDeployment deployment, int sslRedirectPort) {
+        this.reqAuthenticator = requestAuthenticator;
         this.facade = facade;
         this.deployment = deployment;
         this.sslRedirectPort = sslRedirectPort;
@@ -253,7 +255,8 @@ public abstract class OAuthRequestAuthenticator {
         AccessTokenResponse tokenResponse = null;
         strippedOauthParametersRequestUri = stripOauthParametersFromRedirect();
         try {
-            tokenResponse = ServerRequest.invokeAccessCodeToToken(deployment, code, strippedOauthParametersRequestUri);
+            String httpSessionId = reqAuthenticator.getHttpSessionId(true);
+            tokenResponse = ServerRequest.invokeAccessCodeToToken(deployment, code, strippedOauthParametersRequestUri, httpSessionId);
         } catch (ServerRequest.HttpFailure failure) {
             log.error("failed to turn code into token");
             log.error("status from server: " + failure.getStatus());
diff --git a/integration/adapter-core/src/main/java/org/keycloak/adapters/PreAuthActionsHandler.java b/integration/adapter-core/src/main/java/org/keycloak/adapters/PreAuthActionsHandler.java
index e2aff3f..efc5463 100755
--- a/integration/adapter-core/src/main/java/org/keycloak/adapters/PreAuthActionsHandler.java
+++ b/integration/adapter-core/src/main/java/org/keycloak/adapters/PreAuthActionsHandler.java
@@ -7,10 +7,6 @@ import org.keycloak.jose.jws.crypto.RSAProvider;
 import org.keycloak.representations.adapters.action.AdminAction;
 import org.keycloak.representations.adapters.action.LogoutAction;
 import org.keycloak.representations.adapters.action.PushNotBeforeAction;
-import org.keycloak.representations.adapters.action.SessionStats;
-import org.keycloak.representations.adapters.action.SessionStatsAction;
-import org.keycloak.representations.adapters.action.UserStats;
-import org.keycloak.representations.adapters.action.UserStatsAction;
 import org.keycloak.util.JsonSerialization;
 import org.keycloak.util.StreamUtil;
 
@@ -60,14 +56,6 @@ public class PreAuthActionsHandler {
             if (!resolveDeployment()) return true;
             handlePushNotBefore();
             return true;
-        } else if (requestUri.endsWith(AdapterConstants.K_GET_SESSION_STATS)) {
-            if (!resolveDeployment()) return true;
-            handleGetSessionStats();
-            return true;
-        } else if (requestUri.endsWith(AdapterConstants.K_GET_USER_STATS)) {
-            if (!resolveDeployment()) return true;
-            handleGetUserStats();
-            return true;
         } else if (requestUri.endsWith(AdapterConstants.K_VERSION)) {
             handleVersion();
             return true;
@@ -123,14 +111,10 @@ public class PreAuthActionsHandler {
             }
             LogoutAction action = JsonSerialization.readValue(token.getContent(), LogoutAction.class);
             if (!validateAction(action)) return;
-            String user = action.getUser();
-            if (user != null) {
-                log.debug("logout of session for: " + user);
-                userSessionManagement.logoutUser(user);
-            } else if (action.getSession() != null) {
-                userSessionManagement.logoutKeycloakSession(action.getSession());
+            if (action.getAdapterSessionIds() != null) {
+                userSessionManagement.logoutHttpSessions(action.getAdapterSessionIds());
             } else {
-                log.debug("logout of all sessions");
+                log.infof("logout of all sessions for application '%s'", action.getResource());
                 if (action.getNotBefore() > deployment.getNotBefore()) {
                     deployment.setNotBefore(action.getNotBefore());
                 }
@@ -208,50 +192,6 @@ public class PreAuthActionsHandler {
         return true;
     }
 
-    protected void handleGetSessionStats()  {
-        if (log.isTraceEnabled()) {
-            log.trace("K_GET_SESSION_STATS sent");
-        }
-        try {
-            JWSInput token = verifyAdminRequest();
-            if (token == null) return;
-            SessionStatsAction action = JsonSerialization.readValue(token.getContent(), SessionStatsAction.class);
-            if (!validateAction(action)) return;
-            SessionStats stats = new SessionStats();
-            stats.setActiveSessions(userSessionManagement.getActiveSessions());
-            stats.setActiveUsers(userSessionManagement.getActiveUsers().size());
-            if (action.isListUsers() && userSessionManagement.getActiveSessions() > 0) {
-                Map<String, UserStats> list = new HashMap<String, UserStats>();
-                for (String user : userSessionManagement.getActiveUsers()) {
-                    list.put(user, getUserStats(user));
-                }
-                stats.setUsers(list);
-            }
-            facade.getResponse().setStatus(200);
-            facade.getResponse().setHeader("Content-Type", "application/json");
-            JsonSerialization.writeValueToStream(facade.getResponse().getOutputStream(), stats);
-        } catch (Exception e) {
-            throw new RuntimeException(e);
-        }
-    }
-    protected void handleGetUserStats()  {
-        if (log.isTraceEnabled()) {
-            log.trace("K_GET_USER_STATS sent");
-        }
-        try {
-            JWSInput token = verifyAdminRequest();
-            if (token == null) return;
-            UserStatsAction action = JsonSerialization.readValue(token.getContent(), UserStatsAction.class);
-            if (!validateAction(action)) return;
-            String user = action.getUser();
-            UserStats stats = getUserStats(user);
-            facade.getResponse().setStatus(200);
-            facade.getResponse().setHeader("Content-Type", "application/json");
-            JsonSerialization.writeValueToStream(facade.getResponse().getOutputStream(), stats);
-        } catch (Exception e) {
-            throw new RuntimeException(e);
-        }
-    }
     protected void handleVersion()  {
         try {
             facade.getResponse().setStatus(200);
@@ -262,15 +202,4 @@ public class PreAuthActionsHandler {
         }
     }
 
-    protected UserStats getUserStats(String user) {
-        UserStats stats = new UserStats();
-        Long loginTime = userSessionManagement.getUserLoginTime(user);
-        if (loginTime != null) {
-            stats.setLoggedIn(true);
-            stats.setWhenLoggedIn(loginTime);
-        } else {
-            stats.setLoggedIn(false);
-        }
-        return stats;
-    }
 }
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 7dfe62c..3fc5b3d 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
@@ -32,13 +32,13 @@ public class RefreshableKeycloakSecurityContext extends KeycloakSecurityContext 
 
     @Override
     public AccessToken getToken() {
-        refreshExpiredToken();
+        refreshExpiredToken(true);
         return super.getToken();
     }
 
     @Override
     public String getTokenString() {
-        refreshExpiredToken();
+        refreshExpiredToken(true);
         return super.getTokenString();
     }
 
@@ -62,12 +62,19 @@ public class RefreshableKeycloakSecurityContext extends KeycloakSecurityContext 
         this.deployment = deployment;
     }
 
-    public void refreshExpiredToken() {
-        if (log.isTraceEnabled()) {
-            log.trace("checking whether to refresh.");
+    /**
+     * @param checkActive if true, then we won't send refresh request if current accessToken is still active.
+     * @return true if accessToken is active or was successfully refreshed
+     */
+    public boolean refreshExpiredToken(boolean checkActive) {
+        if (checkActive) {
+            if (log.isTraceEnabled()) {
+                log.trace("checking whether to refresh.");
+            }
+            if (isActive()) return true;
         }
-        if (isActive()) return;
-        if (this.deployment == null || refreshToken == null) return; // Might be serialized in HttpSession?
+
+        if (this.deployment == null || refreshToken == null) return false; // Might be serialized in HttpSession?
 
         if (log.isTraceEnabled()) {
             log.trace("Doing refresh");
@@ -77,10 +84,10 @@ public class RefreshableKeycloakSecurityContext extends KeycloakSecurityContext 
             response = ServerRequest.invokeRefresh(deployment, refreshToken);
         } catch (IOException e) {
             log.error("Refresh token failure", e);
-            return;
+            return false;
         } catch (ServerRequest.HttpFailure httpFailure) {
             log.error("Refresh token failure status: " + httpFailure.getStatus() + " " + httpFailure.getError());
-            return;
+            return false;
         }
         if (log.isTraceEnabled()) {
             log.trace("received refresh response");
@@ -100,7 +107,7 @@ public class RefreshableKeycloakSecurityContext extends KeycloakSecurityContext 
         this.token = token;
         this.refreshToken = response.getRefreshToken();
         this.tokenString = tokenString;
-
+        return true;
     }
 
 
diff --git a/integration/adapter-core/src/main/java/org/keycloak/adapters/RequestAuthenticator.java b/integration/adapter-core/src/main/java/org/keycloak/adapters/RequestAuthenticator.java
index 3cf2c91..0b31238 100755
--- a/integration/adapter-core/src/main/java/org/keycloak/adapters/RequestAuthenticator.java
+++ b/integration/adapter-core/src/main/java/org/keycloak/adapters/RequestAuthenticator.java
@@ -111,6 +111,7 @@ public abstract class RequestAuthenticator {
     protected abstract void completeOAuthAuthentication(KeycloakPrincipal<RefreshableKeycloakSecurityContext> principal);
     protected abstract void completeBearerAuthentication(KeycloakPrincipal<RefreshableKeycloakSecurityContext> principal);
     protected abstract boolean isCached();
+    protected abstract String getHttpSessionId(boolean create);
 
     protected void completeAuthentication(BearerTokenRequestAuthenticator bearer) {
         RefreshableKeycloakSecurityContext session = new RefreshableKeycloakSecurityContext(deployment, bearer.getTokenString(), bearer.getToken(), null, null, null);
diff --git a/integration/adapter-core/src/main/java/org/keycloak/adapters/ServerRequest.java b/integration/adapter-core/src/main/java/org/keycloak/adapters/ServerRequest.java
index 9854950..970929b 100755
--- a/integration/adapter-core/src/main/java/org/keycloak/adapters/ServerRequest.java
+++ b/integration/adapter-core/src/main/java/org/keycloak/adapters/ServerRequest.java
@@ -84,21 +84,24 @@ public class ServerRequest {
         if (is != null) is.close();
     }
 
-    public static AccessTokenResponse invokeAccessCodeToToken(KeycloakDeployment deployment, String code, String redirectUri) throws HttpFailure, IOException {
+    public static AccessTokenResponse invokeAccessCodeToToken(KeycloakDeployment deployment, String code, String redirectUri, String sessionId) throws HttpFailure, IOException {
         String codeUrl = deployment.getCodeUrl();
         String client_id = deployment.getResourceName();
         Map<String, String> credentials = deployment.getResourceCredentials();
         HttpClient client = deployment.getClient();
 
-        return invokeAccessCodeToToken(client, deployment.isPublicClient(), code, codeUrl, redirectUri, client_id, credentials);
+        return invokeAccessCodeToToken(client, deployment.isPublicClient(), code, codeUrl, redirectUri, client_id, credentials, sessionId);
     }
 
-    public static AccessTokenResponse invokeAccessCodeToToken(HttpClient client, boolean publicClient, String code, String codeUrl, String redirectUri, String client_id, Map<String, String> credentials) throws IOException, HttpFailure {
+    public static AccessTokenResponse invokeAccessCodeToToken(HttpClient client, boolean publicClient, String code, String codeUrl, String redirectUri, String client_id, Map<String, String> credentials, String sessionId) throws IOException, HttpFailure {
         List<NameValuePair> formparams = new ArrayList<NameValuePair>();
         redirectUri = stripOauthParametersFromRedirect(redirectUri);
         formparams.add(new BasicNameValuePair(OAuth2Constants.GRANT_TYPE, "authorization_code"));
         formparams.add(new BasicNameValuePair(OAuth2Constants.CODE, code));
         formparams.add(new BasicNameValuePair(OAuth2Constants.REDIRECT_URI, redirectUri));
+        if (sessionId != null) {
+            formparams.add(new BasicNameValuePair(AdapterConstants.HTTP_SESSION_ID, sessionId));
+        }
         HttpResponse response = null;
         HttpPost post = new HttpPost(codeUrl);
         if (!publicClient) {
diff --git a/integration/adapter-core/src/main/java/org/keycloak/adapters/UserSessionManagement.java b/integration/adapter-core/src/main/java/org/keycloak/adapters/UserSessionManagement.java
index ca4653a..c89e3ec 100755
--- a/integration/adapter-core/src/main/java/org/keycloak/adapters/UserSessionManagement.java
+++ b/integration/adapter-core/src/main/java/org/keycloak/adapters/UserSessionManagement.java
@@ -1,21 +1,14 @@
 package org.keycloak.adapters;
 
-import java.util.Set;
+import java.util.List;
 
 /**
  * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
  * @version $Revision: 1 $
  */
 public interface UserSessionManagement {
-    int getActiveSessions();
-
-    Long getUserLoginTime(String username);
-
-    Set<String> getActiveUsers();
 
     void logoutAll();
 
-    void logoutUser(String user);
-
-    void logoutKeycloakSession(String id);
+    void logoutHttpSessions(List<String> ids);
 }
diff --git a/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/CatalinaRequestAuthenticator.java b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/CatalinaRequestAuthenticator.java
index aca4db7..a1cb95c 100755
--- a/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/CatalinaRequestAuthenticator.java
+++ b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/CatalinaRequestAuthenticator.java
@@ -18,6 +18,8 @@ import java.security.Principal;
 import java.util.Collections;
 import java.util.Set;
 
+import javax.servlet.http.HttpSession;
+
 /**
  * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
  * @version $Revision: 1 $
@@ -40,7 +42,7 @@ public class CatalinaRequestAuthenticator extends RequestAuthenticator {
 
     @Override
     protected OAuthRequestAuthenticator createOAuthAuthenticator() {
-        return new OAuthRequestAuthenticator(facade, deployment, sslRedirectPort) {
+        return new OAuthRequestAuthenticator(this, facade, deployment, sslRedirectPort) {
             @Override
             protected void saveRequest() {
                 try {
@@ -64,15 +66,15 @@ public class CatalinaRequestAuthenticator extends RequestAuthenticator {
         session.setNote(KeycloakSecurityContext.class.getName(), securityContext);
         String username = securityContext.getToken().getSubject();
         log.debug("userSessionManage.login: " + username);
-        userSessionManagement.login(session, username, securityContext.getToken().getSessionState());
+        userSessionManagement.login(session);
     }
 
     @Override
     protected void completeBearerAuthentication(KeycloakPrincipal<RefreshableKeycloakSecurityContext> principal) {
         RefreshableKeycloakSecurityContext securityContext = principal.getKeycloakSecurityContext();
         Set<String> roles = getRolesFromToken(securityContext);
-        for (String role : roles) {
-            log.info("Bearer role: " + role);
+        if (log.isDebugEnabled()) {
+            log.debug("Completing bearer authentication. Bearer roles: " + roles);
         }
         Principal generalPrincipal = new CatalinaSecurityContextHelper().createPrincipal(request.getContext().getRealm(), principal, roles, securityContext);
         request.setUserPrincipal(generalPrincipal);
@@ -123,4 +125,10 @@ public class CatalinaRequestAuthenticator extends RequestAuthenticator {
             }
         }
     }
+
+    @Override
+    protected String getHttpSessionId(boolean create) {
+        HttpSession session = request.getSession(create);
+        return session != null ? session.getId() : null;
+    }
 }
diff --git a/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/CatalinaUserSessionManagement.java b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/CatalinaUserSessionManagement.java
index c1ac980..ffb806e 100755
--- a/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/CatalinaUserSessionManagement.java
+++ b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/CatalinaUserSessionManagement.java
@@ -1,17 +1,14 @@
 package org.keycloak.adapters.as7;
 
+import org.apache.catalina.Manager;
 import org.apache.catalina.Session;
 import org.apache.catalina.SessionEvent;
 import org.apache.catalina.SessionListener;
 import org.apache.catalina.realm.GenericPrincipal;
 import org.jboss.logging.Logger;
-import org.keycloak.adapters.UserSessionManagement;
 
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
+import java.io.IOException;
+import java.util.List;
 
 /**
  * Manages relationship to users and sessions so that forced admin logout can be implemented
@@ -19,112 +16,50 @@ import java.util.concurrent.ConcurrentHashMap;
  * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
  * @version $Revision: 1 $
  */
-public class CatalinaUserSessionManagement implements SessionListener, UserSessionManagement {
+public class CatalinaUserSessionManagement implements SessionListener {
     private static final Logger log = Logger.getLogger(CatalinaUserSessionManagement.class);
-    protected ConcurrentHashMap<String, UserSessions> userSessionMap = new ConcurrentHashMap<String, UserSessions>();
-    protected ConcurrentHashMap<String, UserSessions> keycloakSessionMap = new ConcurrentHashMap<String, UserSessions>();
 
-    public static class UserSessions {
-        protected String user;
-        protected long loggedIn = System.currentTimeMillis();
-        protected Map<String, String>  keycloakSessionToHttpSession = new HashMap<String, String>();
-        protected Map<String, String>  httpSessionToKeycloakSession = new HashMap<String, String>();
-        protected Map<String, Session> sessions = new HashMap<String, Session>();
-        public long getLoggedIn() {
-            return loggedIn;
-        }
-    }
-
-    public synchronized int getActiveSessions() {
-        return keycloakSessionMap.size();
-    }
-
-    /**
-     *
-     * @param username
-     * @return null if user not logged in
-     */
-    @Override
-    public synchronized Long getUserLoginTime(String username) {
-        UserSessions sessions = userSessionMap.get(username);
-        if (sessions == null) return null;
-        return sessions.getLoggedIn();
+    public void login(Session session) {
+        session.addSessionListener(this);
     }
 
-    @Override
-    public synchronized Set<String> getActiveUsers() {
-        HashSet<String> set = new HashSet<String>();
-        set.addAll(userSessionMap.keySet());
-        return set;
+    public void logoutAll(Manager sessionManager) {
+        Session[] allSessions = sessionManager.findSessions();
+        for (Session session : allSessions) {
+            logoutSession(session);
+        }
     }
 
+    public void logoutHttpSessions(Manager sessionManager, List<String> sessionIds) {
+        log.debug("logoutHttpSessions: " + sessionIds);
 
-    public synchronized void login(Session session, String username, String keycloakSessionId) {
-        String sessionId = session.getId();
-
-        UserSessions sessions = userSessionMap.get(username);
-        if (sessions == null) {
-            sessions = new UserSessions();
-            sessions.user = username;
-            userSessionMap.put(username, sessions);
+        for (String sessionId : sessionIds) {
+            logoutSession(sessionManager, sessionId);
         }
-        keycloakSessionMap.put(keycloakSessionId, sessions);
-        sessions.httpSessionToKeycloakSession.put(sessionId, keycloakSessionId);
-        sessions.keycloakSessionToHttpSession.put(keycloakSessionId, sessionId);
-        sessions.sessions.put(sessionId, session);
-        session.addSessionListener(this);
     }
 
-    @Override
-    public void logoutAll() {
-        for (String user : userSessionMap.keySet()) logoutUser(user);
-    }
+    protected void logoutSession(Manager manager, String httpSessionId) {
+        log.debug("logoutHttpSession: " + httpSessionId);
 
-    @Override
-    public void logoutUser(String user) {
-        log.debug("logoutUser: " + user);
-        UserSessions sessions = null;
-        sessions = userSessionMap.remove(user);
-        if (sessions == null) {
-            log.debug("no session for user: " + user);
+        Session session;
+        try {
+            session = manager.findSession(httpSessionId);
+        } catch (IOException ioe) {
+            log.warn("IO exception when looking for session " + httpSessionId, ioe);
             return;
         }
-        log.debug("found session for user");
-        for (Map.Entry<String, String> entry : sessions.httpSessionToKeycloakSession.entrySet()) {
-            log.debug("invalidating session for user: " + user);
-            String sessionId = entry.getKey();
-            String keycloakSessionId = entry.getValue();
-            Session session = sessions.sessions.get(sessionId);
-            session.setPrincipal(null);
-            session.setAuthType(null);
-            session.getSession().invalidate();
-            keycloakSessionMap.remove(keycloakSessionId);
-        }
-    }
 
-    public synchronized void logoutKeycloakSession(String keycloakSessionId) {
-        log.debug("logoutKeycloakSession: " + keycloakSessionId);
-        UserSessions sessions = keycloakSessionMap.remove(keycloakSessionId);
-        if (sessions == null) {
-            log.debug("no session for keycloak session id: " + keycloakSessionId);
-            return;
-        }
-        String sessionId = sessions.keycloakSessionToHttpSession.remove(keycloakSessionId);
-        if (sessionId == null) {
-            log.debug("no session for keycloak session id: " + keycloakSessionId);
+        logoutSession(session);
+    }
 
-        }
-        sessions.httpSessionToKeycloakSession.remove(sessionId);
-        Session session = sessions.sessions.remove(sessionId);
-        session.setPrincipal(null);
-        session.setAuthType(null);
-        session.getSession().invalidate();
-        if (sessions.keycloakSessionToHttpSession.size() == 0) {
-            userSessionMap.remove(sessions.user);
+    protected void logoutSession(Session session) {
+        try {
+            session.expire();
+        } catch (Exception e) {
+            log.warnf("Session not present or already invalidated.");
         }
     }
 
-
     public void sessionEvent(SessionEvent event) {
         // We only care about session destroyed events
         if (!Session.SESSION_DESTROYED_EVENT.equals(event.getType())
@@ -133,28 +68,11 @@ public class CatalinaUserSessionManagement implements SessionListener, UserSessi
 
         // Look up the single session id associated with this session (if any)
         Session session = event.getSession();
+        log.debugf("Session %s destroyed", session.getId());
+
         GenericPrincipal principal = (GenericPrincipal) session.getPrincipal();
         if (principal == null) return;
         session.setPrincipal(null);
         session.setAuthType(null);
-
-        String username = principal.getUserPrincipal().getName();
-        UserSessions userSessions = userSessionMap.get(username);
-        if (userSessions == null) {
-            return;
-        }
-        String sessionid = session.getId();
-        synchronized (this) {
-            String keycloakSessionId = userSessions.httpSessionToKeycloakSession.remove(sessionid);
-            if (keycloakSessionId != null) {
-                userSessions.keycloakSessionToHttpSession.remove(keycloakSessionId);
-                keycloakSessionMap.remove(keycloakSessionId);
-            }
-            userSessions.sessions.remove(sessionid);
-            if (userSessions.httpSessionToKeycloakSession.size() == 0) {
-                userSessionMap.remove(username);
-            }
-
-        }
     }
 }
diff --git a/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/CatalinaUserSessionManagementWrapper.java b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/CatalinaUserSessionManagementWrapper.java
new file mode 100644
index 0000000..ff7ee07
--- /dev/null
+++ b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/CatalinaUserSessionManagementWrapper.java
@@ -0,0 +1,30 @@
+package org.keycloak.adapters.as7;
+
+import java.util.List;
+
+import org.apache.catalina.Manager;
+import org.keycloak.adapters.UserSessionManagement;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class CatalinaUserSessionManagementWrapper implements UserSessionManagement {
+
+    private final CatalinaUserSessionManagement delegate;
+    private final Manager sessionManager;
+
+    public CatalinaUserSessionManagementWrapper(CatalinaUserSessionManagement delegate, Manager sessionManager) {
+        this.delegate = delegate;
+        this.sessionManager = sessionManager;
+    }
+
+    @Override
+    public void logoutAll() {
+        delegate.logoutAll(sessionManager);
+    }
+
+    @Override
+    public void logoutHttpSessions(List<String> ids) {
+        delegate.logoutHttpSessions(sessionManager, ids);
+    }
+}
diff --git a/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/KeycloakAuthenticatorValve.java b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/KeycloakAuthenticatorValve.java
index eb39756..9bf2c42 100755
--- a/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/KeycloakAuthenticatorValve.java
+++ b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/KeycloakAuthenticatorValve.java
@@ -5,6 +5,7 @@ import org.apache.catalina.Lifecycle;
 import org.apache.catalina.LifecycleEvent;
 import org.apache.catalina.LifecycleException;
 import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.Manager;
 import org.apache.catalina.Session;
 import org.apache.catalina.authenticator.FormAuthenticator;
 import org.apache.catalina.connector.Request;
@@ -127,7 +128,9 @@ public class KeycloakAuthenticatorValve extends FormAuthenticator implements Lif
                 log.trace("invoke");
             }
             CatalinaHttpFacade facade = new CatalinaHttpFacade(request, response);
-            PreAuthActionsHandler handler = new PreAuthActionsHandler(userSessionManagement, deploymentContext, facade);
+            Manager sessionManager = request.getContext().getManager();
+            CatalinaUserSessionManagementWrapper sessionManagementWrapper = new CatalinaUserSessionManagementWrapper(userSessionManagement, sessionManager);
+            PreAuthActionsHandler handler = new PreAuthActionsHandler(sessionManagementWrapper, deploymentContext, facade);
             if (handler.handleRequest()) {
                 return;
             }
@@ -175,18 +178,22 @@ public class KeycloakAuthenticatorValve extends FormAuthenticator implements Lif
         if (session == null) return;
         // just in case session got serialized
         if (session.getDeployment() == null) session.setDeployment(deploymentContext.resolveDeployment(facade));
-        if (session.isActive()) return;
+        if (session.isActive() && !session.getDeployment().isAlwaysRefreshToken()) return;
 
         // FYI: A refresh requires same scope, so same roles will be set.  Otherwise, refresh will fail and token will
         // not be updated
-        session.refreshExpiredToken();
-        if (session.isActive()) return;
+        boolean success = session.refreshExpiredToken(false);
+        if (success && session.isActive()) return;
 
-        request.getSessionInternal().removeNote(KeycloakSecurityContext.class.getName());
+        // Refresh failed, so user is already logged out from keycloak. Cleanup and expire our session
+        Session catalinaSession = request.getSessionInternal();
+        log.debugf("Cleanup and expire session %s after failed refresh", catalinaSession.getId());
+        catalinaSession.removeNote(KeycloakSecurityContext.class.getName());
         request.setUserPrincipal(null);
         request.setAuthType(null);
-        request.getSessionInternal().setPrincipal(null);
-        request.getSessionInternal().setAuthType(null);
+        catalinaSession.setPrincipal(null);
+        catalinaSession.setAuthType(null);
+        catalinaSession.expire();
     }
 
     public void keycloakSaveRequest(Request request) throws IOException {
diff --git a/integration/installed/src/main/java/org/keycloak/adapters/installed/KeycloakInstalled.java b/integration/installed/src/main/java/org/keycloak/adapters/installed/KeycloakInstalled.java
index 32ebfdb..d3ed536 100644
--- a/integration/installed/src/main/java/org/keycloak/adapters/installed/KeycloakInstalled.java
+++ b/integration/installed/src/main/java/org/keycloak/adapters/installed/KeycloakInstalled.java
@@ -227,7 +227,7 @@ public class KeycloakInstalled {
     }
 
     private void processCode(String code, String redirectUri) throws IOException, ServerRequest.HttpFailure, VerificationException {
-        AccessTokenResponse tokenResponse = ServerRequest.invokeAccessCodeToToken(deployment, code, redirectUri);
+        AccessTokenResponse tokenResponse = ServerRequest.invokeAccessCodeToToken(deployment, code, redirectUri, null);
         parseAccessToken(tokenResponse);
     }
 
diff --git a/integration/servlet-oauth-client/src/main/java/org/keycloak/servlet/ServletOAuthClient.java b/integration/servlet-oauth-client/src/main/java/org/keycloak/servlet/ServletOAuthClient.java
index 0e414ec..2420c53 100755
--- a/integration/servlet-oauth-client/src/main/java/org/keycloak/servlet/ServletOAuthClient.java
+++ b/integration/servlet-oauth-client/src/main/java/org/keycloak/servlet/ServletOAuthClient.java
@@ -41,7 +41,8 @@ public class ServletOAuthClient extends AbstractOAuthClient {
     }
 
     private AccessTokenResponse resolveBearerToken(HttpServletRequest request, String redirectUri, String code) throws IOException, ServerRequest.HttpFailure {
-        return ServerRequest.invokeAccessCodeToToken(client, publicClient, code, getUrl(request, codeUrl, false), redirectUri, clientId, credentials);
+        // Don't send sessionId in oauth clients for now
+        return ServerRequest.invokeAccessCodeToToken(client, publicClient, code, getUrl(request, codeUrl, false), redirectUri, clientId, credentials, null);
     }
 
     /**
diff --git a/integration/tomcat7/adapter/src/main/java/org/keycloak/adapters/tomcat7/CatalinaRequestAuthenticator.java b/integration/tomcat7/adapter/src/main/java/org/keycloak/adapters/tomcat7/CatalinaRequestAuthenticator.java
index 6a05be8..8516b1a 100755
--- a/integration/tomcat7/adapter/src/main/java/org/keycloak/adapters/tomcat7/CatalinaRequestAuthenticator.java
+++ b/integration/tomcat7/adapter/src/main/java/org/keycloak/adapters/tomcat7/CatalinaRequestAuthenticator.java
@@ -16,8 +16,11 @@ import java.io.IOException;
 import java.security.Principal;
 import java.util.Collections;
 import java.util.Set;
+import java.util.logging.Level;
 import java.util.logging.Logger;
 
+import javax.servlet.http.HttpSession;
+
 /**
  * @author <a href="mailto:ungarida@gmail.com">Davide Ungari</a>
  * @version $Revision: 1 $
@@ -40,7 +43,7 @@ public class CatalinaRequestAuthenticator extends RequestAuthenticator {
 
     @Override
     protected OAuthRequestAuthenticator createOAuthAuthenticator() {
-        return new OAuthRequestAuthenticator(facade, deployment, sslRedirectPort) {
+        return new OAuthRequestAuthenticator(this, facade, deployment, sslRedirectPort) {
             @Override
             protected void saveRequest() {
                 try {
@@ -63,16 +66,16 @@ public class CatalinaRequestAuthenticator extends RequestAuthenticator {
         session.setAuthType("OAUTH");
         session.setNote(KeycloakSecurityContext.class.getName(), securityContext);
         String username = securityContext.getToken().getSubject();
-        log.finer("userSessionManage.login: " + username);
-        userSessionManagement.login(session, username, securityContext.getToken().getSessionState());
+        log.finer("userSessionManagement.login: " + username);
+        userSessionManagement.login(session);
     }
 
     @Override
     protected void completeBearerAuthentication(KeycloakPrincipal<RefreshableKeycloakSecurityContext> principal) {
         RefreshableKeycloakSecurityContext securityContext = principal.getKeycloakSecurityContext();
         Set<String> roles = getRolesFromToken(securityContext);
-        for (String role : roles) {
-            log.info("Bearer role: " + role);
+        if (log.isLoggable(Level.FINE)) {
+            log.fine("Completing bearer authentication. Bearer roles: " + roles);
         }
         Principal generalPrincipal = new CatalinaSecurityContextHelper().createPrincipal(request.getContext().getRealm(), principal, roles, securityContext);
         request.setUserPrincipal(generalPrincipal);
@@ -123,4 +126,10 @@ public class CatalinaRequestAuthenticator extends RequestAuthenticator {
             }
         }
     }
+
+    @Override
+    protected String getHttpSessionId(boolean create) {
+        HttpSession session = request.getSession(create);
+        return session != null ? session.getId() : null;
+    }
 }
diff --git a/integration/tomcat7/adapter/src/main/java/org/keycloak/adapters/tomcat7/CatalinaUserSessionManagement.java b/integration/tomcat7/adapter/src/main/java/org/keycloak/adapters/tomcat7/CatalinaUserSessionManagement.java
index c21bbb8..66258dd 100755
--- a/integration/tomcat7/adapter/src/main/java/org/keycloak/adapters/tomcat7/CatalinaUserSessionManagement.java
+++ b/integration/tomcat7/adapter/src/main/java/org/keycloak/adapters/tomcat7/CatalinaUserSessionManagement.java
@@ -1,16 +1,13 @@
 package org.keycloak.adapters.tomcat7;
 
+import org.apache.catalina.Manager;
 import org.apache.catalina.Session;
 import org.apache.catalina.SessionEvent;
 import org.apache.catalina.SessionListener;
 import org.apache.catalina.realm.GenericPrincipal;
-import org.keycloak.adapters.UserSessionManagement;
 
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
+import java.io.IOException;
+import java.util.List;
 import java.util.logging.Logger;
 
 /**
@@ -19,105 +16,52 @@ import java.util.logging.Logger;
  * @author <a href="mailto:ungarida@gmail.com">Davide Ungari</a>
  * @version $Revision: 1 $
  */
-public class CatalinaUserSessionManagement implements SessionListener, UserSessionManagement {
-    private static final Logger log = Logger.getLogger(""+CatalinaUserSessionManagement.class);
-    protected ConcurrentHashMap<String, UserSessions> userSessionMap = new ConcurrentHashMap<String, UserSessions>();
-    protected ConcurrentHashMap<String, UserSessions> keycloakSessionMap = new ConcurrentHashMap<String, UserSessions>();
-
-    public static class UserSessions {
-        protected String user;
-        protected long loggedIn = System.currentTimeMillis();
-        protected Map<String, String>  keycloakSessionToHttpSession = new HashMap<String, String>();
-        protected Map<String, String>  httpSessionToKeycloakSession = new HashMap<String, String>();
-        protected Map<String, Session> sessions = new HashMap<String, Session>();
-        public long getLoggedIn() {
-            return loggedIn;
-        }
-    }
+public class CatalinaUserSessionManagement implements SessionListener {
 
-    public synchronized int getActiveSessions() {
-        return keycloakSessionMap.size();
-    }
+    private static final Logger log = Logger.getLogger(""+CatalinaUserSessionManagement.class);
 
-    /**
-     *
-     * @param username
-     * @return null if user not logged in
-     */
-    @Override
-    public synchronized Long getUserLoginTime(String username) {
-        UserSessions sessions = userSessionMap.get(username);
-        if (sessions == null) return null;
-        return sessions.getLoggedIn();
+    public void login(Session session) {
+        session.addSessionListener(this);
     }
 
-    @Override
-    public synchronized Set<String> getActiveUsers() {
-        HashSet<String> set = new HashSet<String>();
-        set.addAll(userSessionMap.keySet());
-        return set;
+    public void logoutAll(Manager sessionManager) {
+        Session[] allSessions = sessionManager.findSessions();
+        for (Session session : allSessions) {
+            logoutSession(session);
+        }
     }
 
+    public void logoutHttpSessions(Manager sessionManager, List<String> sessionIds) {
+        log.fine("logoutHttpSessions: " + sessionIds);
 
-    public synchronized void login(Session session, String username, String keycloakSessionId) {
-        String sessionId = session.getId();
-
-        UserSessions sessions = userSessionMap.get(username);
-        if (sessions == null) {
-            sessions = new UserSessions();
-            sessions.user = username;
-            userSessionMap.put(username, sessions);
+        for (String sessionId : sessionIds) {
+            logoutSession(sessionManager, sessionId);
         }
-        keycloakSessionMap.put(keycloakSessionId, sessions);
-        sessions.httpSessionToKeycloakSession.put(sessionId, keycloakSessionId);
-        sessions.keycloakSessionToHttpSession.put(keycloakSessionId, sessionId);
-        sessions.sessions.put(sessionId, session);
-        session.addSessionListener(this);
     }
 
-    @Override
-    public void logoutAll() {
-        for (String user : userSessionMap.keySet()) logoutUser(user);
-    }
+    protected void logoutSession(Manager manager, String httpSessionId) {
+        log.fine("logoutHttpSession: " + httpSessionId);
 
-    @Override
-    public void logoutUser(String user) {
-        UserSessions sessions = null;
-        sessions = userSessionMap.remove(user);
-        if (sessions == null) {
+        Session session;
+        try {
+            session = manager.findSession(httpSessionId);
+        } catch (IOException ioe) {
+            log.warning("IO exception when looking for session " + httpSessionId);
+            ioe.printStackTrace();
             return;
         }
-        for (Map.Entry<String, String> entry : sessions.httpSessionToKeycloakSession.entrySet()) {
-            String sessionId = entry.getKey();
-            String keycloakSessionId = entry.getValue();
-            Session session = sessions.sessions.get(sessionId);
-            session.setPrincipal(null);
-            session.setAuthType(null);
-            session.getSession().invalidate();
-            keycloakSessionMap.remove(keycloakSessionId);
-        }
-    }
 
-    public synchronized void logoutKeycloakSession(String keycloakSessionId) {
-        UserSessions sessions = keycloakSessionMap.remove(keycloakSessionId);
-        if (sessions == null) {
-            return;
-        }
-        String sessionId = sessions.keycloakSessionToHttpSession.remove(keycloakSessionId);
-        if (sessionId == null) {
+        logoutSession(session);
+    }
 
-        }
-        sessions.httpSessionToKeycloakSession.remove(sessionId);
-        Session session = sessions.sessions.remove(sessionId);
-        session.setPrincipal(null);
-        session.setAuthType(null);
-        session.getSession().invalidate();
-        if (sessions.keycloakSessionToHttpSession.size() == 0) {
-            userSessionMap.remove(sessions.user);
+    protected void logoutSession(Session session) {
+        try {
+            session.expire();
+        } catch (Exception e) {
+            log.warning("Session not present or already invalidated.");
         }
     }
 
-
     public void sessionEvent(SessionEvent event) {
         // We only care about session destroyed events
         if (!Session.SESSION_DESTROYED_EVENT.equals(event.getType())
@@ -126,28 +70,11 @@ public class CatalinaUserSessionManagement implements SessionListener, UserSessi
 
         // Look up the single session id associated with this session (if any)
         Session session = event.getSession();
+        log.fine("Session " + session.getId() + " destroyed");
+
         GenericPrincipal principal = (GenericPrincipal) session.getPrincipal();
         if (principal == null) return;
         session.setPrincipal(null);
         session.setAuthType(null);
-
-        String username = principal.getUserPrincipal().getName();
-        UserSessions userSessions = userSessionMap.get(username);
-        if (userSessions == null) {
-            return;
-        }
-        String sessionid = session.getId();
-        synchronized (this) {
-            String keycloakSessionId = userSessions.httpSessionToKeycloakSession.remove(sessionid);
-            if (keycloakSessionId != null) {
-                userSessions.keycloakSessionToHttpSession.remove(keycloakSessionId);
-                keycloakSessionMap.remove(keycloakSessionId);
-            }
-            userSessions.sessions.remove(sessionid);
-            if (userSessions.httpSessionToKeycloakSession.size() == 0) {
-                userSessionMap.remove(username);
-            }
-
-        }
     }
 }
diff --git a/integration/tomcat7/adapter/src/main/java/org/keycloak/adapters/tomcat7/CatalinaUserSessionManagementWrapper.java b/integration/tomcat7/adapter/src/main/java/org/keycloak/adapters/tomcat7/CatalinaUserSessionManagementWrapper.java
new file mode 100644
index 0000000..b1e8828
--- /dev/null
+++ b/integration/tomcat7/adapter/src/main/java/org/keycloak/adapters/tomcat7/CatalinaUserSessionManagementWrapper.java
@@ -0,0 +1,30 @@
+package org.keycloak.adapters.tomcat7;
+
+import java.util.List;
+
+import org.apache.catalina.Manager;
+import org.keycloak.adapters.UserSessionManagement;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class CatalinaUserSessionManagementWrapper implements UserSessionManagement {
+
+    private final CatalinaUserSessionManagement delegate;
+    private final Manager sessionManager;
+
+    public CatalinaUserSessionManagementWrapper(CatalinaUserSessionManagement delegate, Manager sessionManager) {
+        this.delegate = delegate;
+        this.sessionManager = sessionManager;
+    }
+
+    @Override
+    public void logoutAll() {
+        delegate.logoutAll(sessionManager);
+    }
+
+    @Override
+    public void logoutHttpSessions(List<String> ids) {
+        delegate.logoutHttpSessions(sessionManager, ids);
+    }
+}
diff --git a/integration/tomcat7/adapter/src/main/java/org/keycloak/adapters/tomcat7/KeycloakAuthenticatorValve.java b/integration/tomcat7/adapter/src/main/java/org/keycloak/adapters/tomcat7/KeycloakAuthenticatorValve.java
index 2fd8be4..208882c 100755
--- a/integration/tomcat7/adapter/src/main/java/org/keycloak/adapters/tomcat7/KeycloakAuthenticatorValve.java
+++ b/integration/tomcat7/adapter/src/main/java/org/keycloak/adapters/tomcat7/KeycloakAuthenticatorValve.java
@@ -5,6 +5,7 @@ import org.apache.catalina.Lifecycle;
 import org.apache.catalina.LifecycleEvent;
 import org.apache.catalina.LifecycleException;
 import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.Manager;
 import org.apache.catalina.Session;
 import org.apache.catalina.authenticator.FormAuthenticator;
 import org.apache.catalina.connector.Request;
@@ -133,7 +134,9 @@ public class KeycloakAuthenticatorValve extends FormAuthenticator implements Lif
     public void invoke(Request request, Response response) throws IOException, ServletException {
         try {
             CatalinaHttpFacade facade = new CatalinaHttpFacade(request, response);
-            PreAuthActionsHandler handler = new PreAuthActionsHandler(userSessionManagement, deploymentContext, facade);
+            Manager sessionManager = request.getContext().getManager();
+            CatalinaUserSessionManagementWrapper sessionManagementWrapper = new CatalinaUserSessionManagementWrapper(userSessionManagement, sessionManager);
+            PreAuthActionsHandler handler = new PreAuthActionsHandler(sessionManagementWrapper, deploymentContext, facade);
             if (handler.handleRequest()) {
                 return;
             }
@@ -177,18 +180,22 @@ public class KeycloakAuthenticatorValve extends FormAuthenticator implements Lif
         if (session == null) return;
         // just in case session got serialized
         if (session.getDeployment() == null) session.setDeployment(deploymentContext.resolveDeployment(facade));
-        if (session.isActive()) return;
+        if (session.isActive() && !session.getDeployment().isAlwaysRefreshToken()) return;
 
         // FYI: A refresh requires same scope, so same roles will be set.  Otherwise, refresh will fail and token will
         // not be updated
-        session.refreshExpiredToken();
-        if (session.isActive()) return;
+        boolean success = session.refreshExpiredToken(false);
+        if (success && session.isActive()) return;
 
-        request.getSessionInternal().removeNote(KeycloakSecurityContext.class.getName());
+        // Refresh failed, so user is already logged out from keycloak. Cleanup and expire our session
+        Session catalinaSession = request.getSessionInternal();
+        log.fine("Cleanup and expire session " + catalinaSession + " after failed refresh");
+        catalinaSession.removeNote(KeycloakSecurityContext.class.getName());
         request.setUserPrincipal(null);
         request.setAuthType(null);
-        request.getSessionInternal().setPrincipal(null);
-        request.getSessionInternal().setAuthType(null);
+        catalinaSession.setPrincipal(null);
+        catalinaSession.setAuthType(null);
+        catalinaSession.expire();
     }
 
     public void keycloakSaveRequest(Request request) throws IOException {
diff --git a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/KeycloakUndertowAccount.java b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/KeycloakUndertowAccount.java
index 58cbb02..472bc90 100755
--- a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/KeycloakUndertowAccount.java
+++ b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/KeycloakUndertowAccount.java
@@ -92,14 +92,14 @@ public class KeycloakUndertowAccount implements Account, Serializable, KeycloakA
     public boolean isActive() {
         // this object may have been serialized, so we need to reset realm config/metadata
         RefreshableKeycloakSecurityContext session = getKeycloakSecurityContext();
-        if (session.isActive()) {
+        if (session.isActive() && !session.getDeployment().isAlwaysRefreshToken()) {
             log.debug("session is active");
             return true;
         }
 
-        log.debug("session is not active try refresh");
-        session.refreshExpiredToken();
-        if (!session.isActive()) {
+        log.debug("session is not active or refresh is enforced. Try refresh");
+        boolean success = session.refreshExpiredToken(false);
+        if (!success || !session.isActive()) {
             log.debug("session is not active return with failure");
 
             return false;
diff --git a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/ServletRequestAuthenticator.java b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/ServletRequestAuthenticator.java
index c46f477..5416d3c 100755
--- a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/ServletRequestAuthenticator.java
+++ b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/ServletRequestAuthenticator.java
@@ -18,7 +18,9 @@ package org.keycloak.adapters.undertow;
 
 import io.undertow.security.api.SecurityContext;
 import io.undertow.server.HttpServerExchange;
+import io.undertow.server.session.Session;
 import io.undertow.servlet.handlers.ServletRequestContext;
+import io.undertow.util.Sessions;
 import org.keycloak.KeycloakPrincipal;
 import org.keycloak.KeycloakSecurityContext;
 import org.keycloak.adapters.HttpFacade;
@@ -45,9 +47,7 @@ public class ServletRequestAuthenticator extends UndertowRequestAuthenticator {
 
     @Override
     protected boolean isCached() {
-        final ServletRequestContext servletRequestContext = exchange.getAttachment(ServletRequestContext.ATTACHMENT_KEY);
-        HttpServletRequest req = (HttpServletRequest) servletRequestContext.getServletRequest();
-        HttpSession session = req.getSession(false);
+        HttpSession session = getSession(false);
         if (session == null) {
             log.debug("session was null, returning null");
             return false;
@@ -63,10 +63,12 @@ public class ServletRequestAuthenticator extends UndertowRequestAuthenticator {
             securityContext.authenticationComplete(account, "KEYCLOAK", false);
             propagateKeycloakContext( account);
             return true;
+        } else {
+            log.debug("Refresh failed. Account was not active. Returning null and invalidating Http session");
+            session.setAttribute(KeycloakUndertowAccount.class.getName(), null);
+            session.invalidate();
+            return false;
         }
-        log.debug("Account was not active, returning null");
-        session.setAttribute(KeycloakUndertowAccount.class.getName(), null);
-        return false;
     }
 
     @Override
@@ -80,10 +82,9 @@ public class ServletRequestAuthenticator extends UndertowRequestAuthenticator {
     @Override
     protected void login(KeycloakAccount account) {
         final ServletRequestContext servletRequestContext = exchange.getAttachment(ServletRequestContext.ATTACHMENT_KEY);
-        HttpServletRequest req = (HttpServletRequest) servletRequestContext.getServletRequest();
-        HttpSession session = req.getSession(true);
+        HttpSession session = getSession(true);
         session.setAttribute(KeycloakUndertowAccount.class.getName(), account);
-        userSessionManagement.login(servletRequestContext.getDeployment().getSessionManager(), session.getId(), account.getPrincipal().getName(), account.getKeycloakSecurityContext().getToken().getSessionState());
+        userSessionManagement.login(servletRequestContext.getDeployment().getSessionManager());
 
     }
 
@@ -91,4 +92,16 @@ public class ServletRequestAuthenticator extends UndertowRequestAuthenticator {
     protected KeycloakUndertowAccount createAccount(KeycloakPrincipal<RefreshableKeycloakSecurityContext> principal) {
         return new KeycloakUndertowAccount(principal);
     }
+
+    @Override
+    protected String getHttpSessionId(boolean create) {
+        HttpSession session = getSession(create);
+        return session != null ? session.getId() : null;
+    }
+
+    protected HttpSession getSession(boolean create) {
+        final ServletRequestContext servletRequestContext = exchange.getAttachment(ServletRequestContext.ATTACHMENT_KEY);
+        HttpServletRequest req = (HttpServletRequest) servletRequestContext.getServletRequest();
+        return req.getSession(create);
+    }
 }
diff --git a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/SessionManagementBridge.java b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/SessionManagementBridge.java
index 0bdd434..839d39e 100755
--- a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/SessionManagementBridge.java
+++ b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/SessionManagementBridge.java
@@ -19,6 +19,7 @@ package org.keycloak.adapters.undertow;
 import io.undertow.server.session.SessionManager;
 import org.keycloak.adapters.UserSessionManagement;
 
+import java.util.List;
 import java.util.Set;
 
 /**
@@ -36,32 +37,12 @@ public class SessionManagementBridge implements UserSessionManagement {
     }
 
     @Override
-    public int getActiveSessions() {
-        return userSessionManagement.getActiveSessions();
-    }
-
-    @Override
-    public Long getUserLoginTime(String username) {
-        return userSessionManagement.getUserLoginTime(username);
-    }
-
-    @Override
-    public Set<String> getActiveUsers() {
-        return userSessionManagement.getActiveUsers();
-    }
-
-    @Override
     public void logoutAll() {
         userSessionManagement.logoutAll(sessionManager);
     }
 
     @Override
-    public void logoutUser(String user) {
-        userSessionManagement.logoutUser(sessionManager, user);
-    }
-
-    @Override
-    public void logoutKeycloakSession(String id) {
-        userSessionManagement.logoutKeycloakSession(sessionManager, id);
+    public void logoutHttpSessions(List<String> ids) {
+        userSessionManagement.logoutHttpSessions(sessionManager, ids);
     }
 }
diff --git a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/UndertowRequestAuthenticator.java b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/UndertowRequestAuthenticator.java
index 79435ae..671f2e7 100755
--- a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/UndertowRequestAuthenticator.java
+++ b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/UndertowRequestAuthenticator.java
@@ -54,7 +54,7 @@ public abstract class UndertowRequestAuthenticator extends RequestAuthenticator 
 
     @Override
     protected OAuthRequestAuthenticator createOAuthAuthenticator() {
-        return new OAuthRequestAuthenticator(facade, deployment, sslRedirectPort) {
+        return new OAuthRequestAuthenticator(this, facade, deployment, sslRedirectPort) {
             @Override
             protected void saveRequest() {
                 // todo
@@ -73,9 +73,7 @@ public abstract class UndertowRequestAuthenticator extends RequestAuthenticator 
     protected void login(KeycloakAccount account) {
         Session session = Sessions.getOrCreateSession(exchange);
         session.setAttribute(KeycloakUndertowAccount.class.getName(), account);
-        String username = account.getPrincipal().getName();
-        String keycloakSessionId = account.getKeycloakSecurityContext().getToken().getSessionState();
-        userSessionManagement.login(session.getSessionManager(), session.getId(), username, keycloakSessionId);
+        userSessionManagement.login(session.getSessionManager());
     }
 
 
@@ -90,24 +88,37 @@ public abstract class UndertowRequestAuthenticator extends RequestAuthenticator 
     protected boolean isCached() {
         Session session = Sessions.getSession(exchange);
         if (session == null) {
-            log.info("session was null, returning null");
+            log.debug("session was null, returning null");
             return false;
         }
         KeycloakUndertowAccount account = (KeycloakUndertowAccount)session.getAttribute(KeycloakUndertowAccount.class.getName());
         if (account == null) {
-            log.info("Account was not in session, returning null");
+            log.debug("Account was not in session, returning null");
             return false;
         }
         account.setDeployment(deployment);
         if (account.isActive()) {
-            log.info("Cached account found");
+            log.debug("Cached account found");
             securityContext.authenticationComplete(account, "KEYCLOAK", false);
             propagateKeycloakContext( account);
             return true;
+        } else {
+            log.debug("Account was not active, returning false");
+            session.removeAttribute(KeycloakUndertowAccount.class.getName());
+            session.invalidate(exchange);
+            return false;
+        }
+    }
+
+    @Override
+    protected String getHttpSessionId(boolean create) {
+        if (create) {
+            Session session = Sessions.getOrCreateSession(exchange);
+            return session.getId();
+        } else {
+            Session session = Sessions.getSession(exchange);
+            return session != null ? session.getId() : null;
         }
-        log.info("Account was not active, returning false");
-        session.removeAttribute(KeycloakUndertowAccount.class.getName());
-        return false;
     }
 
     /**
diff --git a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/UndertowUserSessionManagement.java b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/UndertowUserSessionManagement.java
index f39fe6a..cc0a7c5 100755
--- a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/UndertowUserSessionManagement.java
+++ b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/UndertowUserSessionManagement.java
@@ -27,6 +27,7 @@ import org.jboss.logging.Logger;
 
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
@@ -40,106 +41,35 @@ import java.util.concurrent.ConcurrentHashMap;
 public class UndertowUserSessionManagement implements SessionListener {
     private static final Logger log = Logger.getLogger(UndertowUserSessionManagement.class);
     private static final String AUTH_SESSION_NAME = CachedAuthenticatedSessionHandler.class.getName() + ".AuthenticatedSession";
-    protected ConcurrentHashMap<String, UserSessions> userSessionMap = new ConcurrentHashMap<String, UserSessions>();
-    protected ConcurrentHashMap<String, UserSessions> keycloakSessionMap = new ConcurrentHashMap<String, UserSessions>();
     protected volatile boolean registered;
 
-
-    public static class UserSessions {
-        protected String user;
-        protected long loggedIn = System.currentTimeMillis();
-        protected Map<String, String>  keycloakSessionToHttpSession = new HashMap<String, String>();
-        protected Map<String, String>  httpSessionToKeycloakSession = new HashMap<String, String>();
-        public long getLoggedIn() {
-            return loggedIn;
-        }
-    }
-
-    public synchronized int getActiveSessions() {
-        return keycloakSessionMap.size();
-    }
-
-    /**
-     *
-     * @param username
-     * @return null if user not logged in
-     */
-    public synchronized Long getUserLoginTime(String username) {
-        UserSessions sessions = userSessionMap.get(username);
-        if (sessions == null) return null;
-        return sessions.getLoggedIn();
-    }
-
-    public synchronized Set<String> getActiveUsers() {
-        HashSet<String> set = new HashSet<String>();
-        set.addAll(userSessionMap.keySet());
-        return set;
-    }
-
-    public synchronized void login(SessionManager manager, String sessionId, String username, String keycloakSessionId) {
-        UserSessions sessions = userSessionMap.get(username);
-        if (sessions == null) {
-            sessions = new UserSessions();
-            sessions.user = username;
-            userSessionMap.put(username, sessions);
-        }
-        sessions.httpSessionToKeycloakSession.put(sessionId, keycloakSessionId);
-        sessions.keycloakSessionToHttpSession.put(keycloakSessionId, sessionId);
-        keycloakSessionMap.put(keycloakSessionId, sessions);
+    public void login(SessionManager manager) {
         if (!registered) {
             manager.registerSessionListener(this);
             registered = true;
         }
     }
 
-    public synchronized void logoutAll(SessionManager manager) {
-        for (String user : userSessionMap.keySet()) logoutUser(manager, user);
+    public void logoutAll(SessionManager manager) {
+        Set<String> allSessions = manager.getAllSessions();
+        for (String sessionId : allSessions) logoutSession(manager, sessionId);
     }
 
-    public synchronized void logoutUser(SessionManager manager, String user) {
-        log.debug("logoutUser: " + user);
-        UserSessions sessions = null;
-        sessions = userSessionMap.remove(user);
-        if (sessions == null) {
-            log.debug("no session for user: " + user);
-            return;
-        }
-        log.debug("found session for user");
-        for (Map.Entry<String, String> entry : sessions.httpSessionToKeycloakSession.entrySet()) {
-            log.debug("invalidating session for user: " + user);
-            String sessionId = entry.getKey();
-            String keycloakSessionId = entry.getValue();
-            Session session = getSessionById(manager, sessionId);
-            try {
-                session.invalidate(null);
-            } catch (Exception e) {
-                log.warn("Session already invalidated.");
-            }
-            keycloakSessionMap.remove(keycloakSessionId);
-        }
-    }
+    public void logoutHttpSessions(SessionManager manager, List<String> sessionIds) {
+        log.debug("logoutHttpSessions: " + sessionIds);
 
-    public synchronized void logoutKeycloakSession(SessionManager manager, String keycloakSessionId) {
-        log.debug("logoutKeycloakSession: " + keycloakSessionId);
-        UserSessions sessions = keycloakSessionMap.remove(keycloakSessionId);
-        if (sessions == null) {
-            log.debug("no session for keycloak session id: " + keycloakSessionId);
-            return;
+        for (String sessionId : sessionIds) {
+            logoutSession(manager, sessionId);
         }
-        String sessionId = sessions.keycloakSessionToHttpSession.remove(keycloakSessionId);
-        if (sessionId == null) {
-            log.debug("no session for keycloak session id: " + keycloakSessionId);
+    }
 
-        }
-        sessions.httpSessionToKeycloakSession.remove(sessionId);
-        Session session = getSessionById(manager, sessionId);
+    protected void logoutSession(SessionManager manager, String httpSessionId) {
+        log.debug("logoutHttpSession: " + httpSessionId);
+        Session session = getSessionById(manager, httpSessionId);
         try {
             session.invalidate(null);
         } catch (Exception e) {
-            log.warn("Session already invalidated.");
-        }
-        if (sessions.keycloakSessionToHttpSession.size() == 0) {
-            userSessionMap.remove(sessions.user);
+            log.warnf("Session %s not present or already invalidated.", httpSessionId);
         }
     }
 
@@ -188,23 +118,6 @@ public class UndertowUserSessionManagement implements SessionListener {
         // Look up the single session id associated with this session (if any)
         String username = getUsernameFromSession(session);
         log.debugf("Session destroyed for user: %s, sessionId: %s", username, session.getId());
-        if (username == null) return;
-        String sessionId = session.getId();
-        UserSessions userSessions = userSessionMap.get(username);
-        if (userSessions == null) {
-            return;
-        }
-        synchronized (this) {
-            String keycloakSessionId = userSessions.httpSessionToKeycloakSession.remove(sessionId);
-            if (keycloakSessionId != null) {
-                userSessions.keycloakSessionToHttpSession.remove(keycloakSessionId);
-                keycloakSessionMap.remove(keycloakSessionId);
-            }
-            if (userSessions.httpSessionToKeycloakSession.size() == 0) {
-                userSessionMap.remove(username);
-            }
-
-        }
     }
 
     protected String getUsernameFromSession(Session session) {
@@ -217,23 +130,6 @@ public class UndertowUserSessionManagement implements SessionListener {
 
     @Override
     public void sessionIdChanged(Session session, String oldSessionId) {
-        String username = getUsernameFromSession(session);
-        if (username == null) return;
-        String sessionId = session.getId();
-
-        UserSessions userSessions = userSessionMap.get(username);
-        if (userSessions == null) {
-            return;
-        }
-
-        synchronized (this) {
-            String keycloakSessionId = userSessions.httpSessionToKeycloakSession.remove(oldSessionId);
-            if (keycloakSessionId != null) {
-                userSessions.keycloakSessionToHttpSession.remove(keycloakSessionId);
-                userSessions.keycloakSessionToHttpSession.put(keycloakSessionId, sessionId);
-                userSessions.httpSessionToKeycloakSession.put(sessionId, keycloakSessionId);
-            }
-        }
     }
 
     @Override
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/OpenIDConnect.java b/services/src/main/java/org/keycloak/protocol/oidc/OpenIDConnect.java
index c67960c..e520d8d 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/OpenIDConnect.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/OpenIDConnect.java
@@ -142,7 +142,7 @@ public class OpenIDConnect implements LoginProtocol {
         ApacheHttpClient4Executor executor = ResourceAdminManager.createExecutor();
 
         try {
-            new ResourceAdminManager().logoutApplication(uriInfo.getRequestUri(), realm, app, null, userSession.getId(), executor, 0);
+            new ResourceAdminManager().logoutApplication(uriInfo.getRequestUri(), realm, app, clientSession, executor, 0);
         } finally {
             executor.getHttpClient().getConnectionManager().shutdown();
         }
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/OpenIDConnectService.java b/services/src/main/java/org/keycloak/protocol/oidc/OpenIDConnectService.java
index b88648e..db16b48 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/OpenIDConnectService.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/OpenIDConnectService.java
@@ -14,6 +14,7 @@ import org.keycloak.Config;
 import org.keycloak.OAuth2Constants;
 import org.keycloak.OAuthErrorException;
 import org.keycloak.RSATokenVerifier;
+import org.keycloak.adapters.AdapterConstants;
 import org.keycloak.events.Details;
 import org.keycloak.events.Errors;
 import org.keycloak.events.EventBuilder;
@@ -611,6 +612,13 @@ public class OpenIDConnectService {
                     .build();
         }
 
+        String httpSessionId = formData.getFirst(AdapterConstants.HTTP_SESSION_ID);
+        if (httpSessionId != null) {
+            logger.debugf("Http Session '%s' saved in ClientSession for client '%s'", httpSessionId, client.getClientId());
+            event.detail(AdapterConstants.HTTP_SESSION_ID, httpSessionId);
+            clientSession.setNote(AdapterConstants.HTTP_SESSION_ID, httpSessionId);
+        }
+
         AccessToken token = tokenManager.createClientAccessToken(accessCode.getRequestedRoles(), realm, client, user, userSession);
 
         try {
diff --git a/services/src/main/java/org/keycloak/services/managers/ResourceAdminManager.java b/services/src/main/java/org/keycloak/services/managers/ResourceAdminManager.java
index 105751f..537951c 100755
--- a/services/src/main/java/org/keycloak/services/managers/ResourceAdminManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/ResourceAdminManager.java
@@ -17,10 +17,7 @@ import org.keycloak.models.UserSessionModel;
 import org.keycloak.protocol.oidc.TokenManager;
 import org.keycloak.representations.adapters.action.LogoutAction;
 import org.keycloak.representations.adapters.action.PushNotBeforeAction;
-import org.keycloak.representations.adapters.action.SessionStats;
-import org.keycloak.representations.adapters.action.SessionStatsAction;
 import org.keycloak.representations.adapters.action.UserStats;
-import org.keycloak.representations.adapters.action.UserStatsAction;
 import org.keycloak.services.util.HttpClientBuilder;
 import org.keycloak.services.util.ResolveRelative;
 import org.keycloak.util.StringPropertyReplacer;
@@ -29,8 +26,9 @@ import org.keycloak.util.Time;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.UriBuilder;
 import java.net.URI;
+import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashMap;
-import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 
@@ -41,17 +39,6 @@ import java.util.Map;
 public class ResourceAdminManager {
     protected static Logger logger = Logger.getLogger(ResourceAdminManager.class);
 
-    public SessionStats getSessionStats(URI requestUri, KeycloakSession session, RealmModel realm, ApplicationModel application, boolean users) {
-        ApacheHttpClient4Executor executor = createExecutor();
-
-        try {
-            return getSessionStats(requestUri, session, realm, application, users, executor);
-        } finally {
-            executor.getHttpClient().getConnectionManager().shutdown();
-        }
-
-    }
-
     public static ApacheHttpClient4Executor createExecutor() {
         HttpClient client = new HttpClientBuilder()
                 .disableTrustManager() // todo fix this, should have a trust manager or a good default
@@ -59,49 +46,6 @@ public class ResourceAdminManager {
         return new ApacheHttpClient4Executor(client);
     }
 
-    public SessionStats getSessionStats(URI requestUri, KeycloakSession session, RealmModel realm, ApplicationModel application, boolean users, ApacheHttpClient4Executor client) {
-        String managementUrl = getManagementUrl(requestUri, application);
-        if (managementUrl != null) {
-            SessionStatsAction adminAction = new SessionStatsAction(TokenIdGenerator.generateId(), Time.currentTime() + 30, application.getName());
-            adminAction.setListUsers(users);
-            String token = new TokenManager().encodeToken(realm, adminAction);
-            logger.debugv("session stats for application: {0} url: {1}", application.getName(), managementUrl);
-            ClientRequest request = client.createRequest(UriBuilder.fromUri(managementUrl).path(AdapterConstants.K_GET_SESSION_STATS).build().toString());
-            ClientResponse<SessionStats> response = null;
-            try {
-                response = request.body(MediaType.TEXT_PLAIN_TYPE, token).post(SessionStats.class);
-            } catch (Exception e) {
-                throw new RuntimeException(e);
-            }
-            try {
-                if (response.getStatus() != 200) {
-                    logger.warn("Failed to get stats: " + response.getStatus());
-                    return null;
-                }
-                SessionStats stats = response.getEntity();
-
-                // replace with username
-                if (users && stats.getUsers() != null) {
-                    Map<String, UserStats> newUsers = new HashMap<String, UserStats>();
-                    for (Map.Entry<String, UserStats> entry : stats.getUsers().entrySet()) {
-                        UserModel user = session.users().getUserById(entry.getKey(), realm);
-                        if (user == null) continue;
-                        newUsers.put(user.getUsername(), entry.getValue());
-
-                    }
-                    stats.setUsers(newUsers);
-                }
-                return stats;
-            } finally {
-                response.releaseConnection();
-            }
-        } else {
-            logger.debug("no management url.");
-            return null;
-        }
-
-    }
-
     public static String getManagementUrl(URI requestUri, ApplicationModel application) {
         String mgmtUrl = application.getManagementUrl();
         if (mgmtUrl == null || mgmtUrl.equals("")) {
@@ -111,77 +55,47 @@ public class ResourceAdminManager {
         // this is to support relative admin urls when keycloak and applications are deployed on the same machine
         String absoluteURI = ResolveRelative.resolveRelativeUri(requestUri, mgmtUrl);
 
-        // this is for resolving URI like "http://${jboss.home.name}:8080/..." in order to send request to same machine and avoid LB in cluster env
+        // this is for resolving URI like "http://${jboss.host.name}:8080/..." in order to send request to same machine and avoid request to LB in cluster environment
         return StringPropertyReplacer.replaceProperties(absoluteURI);
     }
 
-    public UserStats getUserStats(URI requestUri, RealmModel realm, ApplicationModel application, UserModel user) {
-        ApacheHttpClient4Executor executor = createExecutor();
-
-        try {
-            return getUserStats(requestUri, realm, application, user, executor);
-        } finally {
-            executor.getHttpClient().getConnectionManager().shutdown();
-        }
-
+    public void logoutUser(URI requestUri, RealmModel realm, UserModel user, KeycloakSession keycloakSession) {
+        List<UserSessionModel> userSessions = keycloakSession.sessions().getUserSessions(realm, user);
+        logoutUserSessions(requestUri, realm, userSessions);
     }
 
+    protected void logoutUserSessions(URI requestUri, RealmModel realm, List<UserSessionModel> userSessions) {
+        ApacheHttpClient4Executor executor = createExecutor();
 
-    public UserStats getUserStats(URI requestUri, RealmModel realm, ApplicationModel application, UserModel user, ApacheHttpClient4Executor client) {
-        String managementUrl = getManagementUrl(requestUri, application);
-        if (managementUrl != null) {
-            UserStatsAction adminAction = new UserStatsAction(TokenIdGenerator.generateId(), Time.currentTime() + 30, application.getName(), user.getId());
-            String token = new TokenManager().encodeToken(realm, adminAction);
-            logger.debugv("session stats for application: {0} url: {1}", application.getName(), managementUrl);
-            ClientRequest request = client.createRequest(UriBuilder.fromUri(managementUrl).path(AdapterConstants.K_GET_USER_STATS).build().toString());
-            ClientResponse<UserStats> response = null;
-            try {
-                response = request.body(MediaType.TEXT_PLAIN_TYPE, token).post(UserStats.class);
-            } catch (Exception e) {
-                throw new RuntimeException(e);
+        try {
+            // Map from "app" to clientSessions for this app
+            Map<ApplicationModel, List<ClientSessionModel>> clientSessions = new HashMap<ApplicationModel, List<ClientSessionModel>>();
+            for (UserSessionModel userSession : userSessions) {
+                putClientSessions(clientSessions, userSession);
             }
 
-            try {
-                if (response.getStatus() != 200) {
-                    logger.warn("Failed to get stats: " + response.getStatus());
-                    return null;
-                }
-                UserStats stats = response.getEntity();
-                return stats;
-            } finally {
-                response.releaseConnection();
+            logger.debugv("logging out {0} resources ", clientSessions.size());
+            logger.infov("logging out resources: " + clientSessions);
+
+            for (Map.Entry<ApplicationModel, List<ClientSessionModel>> entry : clientSessions.entrySet()) {
+                logoutApplication(requestUri, realm, entry.getKey(), entry.getValue(), executor, 0);
             }
-        } else {
-            logger.debug("no management url.");
-            return null;
+        } finally {
+            executor.getHttpClient().getConnectionManager().shutdown();
         }
-
     }
 
-    public void logoutUser(URI requestUri, RealmModel realm, String user, UserSessionModel session) {
-        ApacheHttpClient4Executor executor = createExecutor();
-
-        try {
-            List<ApplicationModel> resources;
-            if (session != null) {
-                resources = new LinkedList<ApplicationModel>();
-
-                for (ClientSessionModel clientSession : session.getClientSessions()) {
-                    ClientModel client = clientSession.getClient();
-                    if (client instanceof ApplicationModel) {
-                        resources.add((ApplicationModel) client);
-                    }
+    private void putClientSessions(Map<ApplicationModel, List<ClientSessionModel>> clientSessions, UserSessionModel userSession) {
+        for (ClientSessionModel clientSession : userSession.getClientSessions()) {
+            ClientModel client = clientSession.getClient();
+            if (client instanceof ApplicationModel) {
+                List<ClientSessionModel> curClientSessions = clientSessions.get(client);
+                if (curClientSessions == null) {
+                    curClientSessions = new ArrayList<ClientSessionModel>();
+                    clientSessions.put((ApplicationModel)client, curClientSessions);
                 }
-            } else {
-                resources = realm.getApplications();
-            }
-
-            logger.debugv("logging out {0} resources ", resources.size());
-            for (ApplicationModel resource : resources) {
-                logoutApplication(requestUri, realm, resource, user, session != null ? session.getId() : null, executor, 0);
+                curClientSessions.add(clientSession);
             }
-        } finally {
-            executor.getHttpClient().getConnectionManager().shutdown();
         }
     }
 
@@ -189,17 +103,12 @@ public class ResourceAdminManager {
         ApacheHttpClient4Executor executor = createExecutor();
 
         try {
-            List<ApplicationModel> resources = new LinkedList<ApplicationModel>();
-            for (ClientSessionModel clientSession : session.getClientSessions()) {
-                ClientModel client = clientSession.getClient();
-                if (client instanceof ApplicationModel) {
-                    resources.add((ApplicationModel) client);
-                }
-            }
+            Map<ApplicationModel, List<ClientSessionModel>> clientSessions = new HashMap<ApplicationModel, List<ClientSessionModel>>();
+            putClientSessions(clientSessions, session);
 
-            logger.debugv("logging out {0} resources ", resources.size());
-            for (ApplicationModel resource : resources) {
-                logoutApplication(requestUri, realm, resource, null, session.getId(), executor, 0);
+            logger.debugv("logging out {0} resources ", clientSessions.size());
+            for (Map.Entry<ApplicationModel, List<ClientSessionModel>> entry : clientSessions.entrySet()) {
+                logoutApplication(requestUri, realm, entry.getKey(), entry.getValue(), executor, 0);
             }
         } finally {
             executor.getHttpClient().getConnectionManager().shutdown();
@@ -214,32 +123,57 @@ public class ResourceAdminManager {
             List<ApplicationModel> resources = realm.getApplications();
             logger.debugv("logging out {0} resources ", resources.size());
             for (ApplicationModel resource : resources) {
-                logoutApplication(requestUri, realm, resource, null, null, executor, realm.getNotBefore());
+                logoutApplication(requestUri, realm, resource, (List<ClientSessionModel>)null, executor, realm.getNotBefore());
             }
         } finally {
             executor.getHttpClient().getConnectionManager().shutdown();
         }
     }
 
-    public void logoutApplication(URI requestUri, RealmModel realm, ApplicationModel resource, String user, String session) {
+    public void logoutApplication(URI requestUri, RealmModel realm, ApplicationModel resource, List<UserSessionModel> userSessions) {
         ApacheHttpClient4Executor executor = createExecutor();
 
         try {
             resource.setNotBefore(Time.currentTime());
-            logoutApplication(requestUri, realm, resource, user, session, executor, resource.getNotBefore());
+
+            List<ClientSessionModel> ourAppClientSessions = null;
+            if (userSessions != null) {
+                Map<ApplicationModel, List<ClientSessionModel>> clientSessions = new HashMap<ApplicationModel, List<ClientSessionModel>>();
+                for (UserSessionModel userSession : userSessions) {
+                    putClientSessions(clientSessions, userSession);
+                }
+                ourAppClientSessions = clientSessions.get(resource);
+            }
+
+            logoutApplication(requestUri, realm, resource, ourAppClientSessions, executor, resource.getNotBefore());
         } finally {
             executor.getHttpClient().getConnectionManager().shutdown();
         }
 
     }
 
+    public boolean logoutApplication(URI requestUri, RealmModel realm, ApplicationModel resource, ClientSessionModel clientSession, ApacheHttpClient4Executor client, int notBefore) {
+        return logoutApplication(requestUri, realm, resource, Arrays.asList(clientSession), client, notBefore);
+    }
 
-    public boolean logoutApplication(URI requestUri, RealmModel realm, ApplicationModel resource, String user, String session, ApacheHttpClient4Executor client, int notBefore) {
+    protected boolean logoutApplication(URI requestUri, RealmModel realm, ApplicationModel resource, List<ClientSessionModel> clientSessions, ApacheHttpClient4Executor client, int notBefore) {
         String managementUrl = getManagementUrl(requestUri, resource);
         if (managementUrl != null) {
-            LogoutAction adminAction = new LogoutAction(TokenIdGenerator.generateId(), Time.currentTime() + 30, resource.getName(), user, session, notBefore);
+
+            List<String> adapterSessionIds = null;
+            if (clientSessions != null && clientSessions.size() > 0) {
+                adapterSessionIds = new ArrayList<String>();
+                for (ClientSessionModel clientSession : clientSessions) {
+                    String adapterSessionId = clientSession.getNote(AdapterConstants.HTTP_SESSION_ID);
+                    if (adapterSessionId != null) {
+                        adapterSessionIds.add(adapterSessionId);
+                    }
+                }
+            }
+
+            LogoutAction adminAction = new LogoutAction(TokenIdGenerator.generateId(), Time.currentTime() + 30, resource.getName(), adapterSessionIds, notBefore);
             String token = new TokenManager().encodeToken(realm, adminAction);
-            logger.debugv("logout user: {0} resource: {1} url: {2}", user, resource.getName(), managementUrl);
+            logger.debugv("logout resource {0} url: {1} sessionIds: " + adapterSessionIds, resource.getName(), managementUrl);
             ClientRequest request = client.createRequest(UriBuilder.fromUri(managementUrl).path(AdapterConstants.K_LOGOUT).build().toString());
             ClientResponse response;
             try {
@@ -292,7 +226,7 @@ public class ResourceAdminManager {
             String token = new TokenManager().encodeToken(realm, adminAction);
             logger.debugv("pushRevocation resource: {0} url: {1}", resource.getName(), managementUrl);
             ClientRequest request = client.createRequest(UriBuilder.fromUri(managementUrl).path(AdapterConstants.K_PUSH_NOT_BEFORE).build().toString());
-            ClientResponse response = null;
+            ClientResponse response;
             try {
                 response = request.body(MediaType.TEXT_PLAIN_TYPE, token).post();
             } catch (Exception e) {
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ApplicationResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ApplicationResource.java
index 237bf44..e804161 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/ApplicationResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/ApplicationResource.java
@@ -13,8 +13,6 @@ import org.keycloak.models.UserSessionModel;
 import org.keycloak.models.utils.KeycloakModelUtils;
 import org.keycloak.models.utils.ModelToRepresentation;
 import org.keycloak.models.utils.RepresentationToModel;
-import org.keycloak.representations.adapters.action.SessionStats;
-import org.keycloak.representations.adapters.action.UserStats;
 import org.keycloak.representations.idm.ApplicationRepresentation;
 import org.keycloak.representations.idm.CredentialRepresentation;
 import org.keycloak.representations.idm.UserSessionRepresentation;
@@ -27,7 +25,6 @@ import org.keycloak.util.JsonSerialization;
 
 import javax.ws.rs.Consumes;
 import javax.ws.rs.DELETE;
-import javax.ws.rs.DefaultValue;
 import javax.ws.rs.GET;
 import javax.ws.rs.POST;
 import javax.ws.rs.PUT;
@@ -286,35 +283,6 @@ public class ApplicationResource {
     }
 
     /**
-     * If the application has an admin URL, query it directly for session stats.
-     *
-     * @param users whether to include users logged in.
-     * @return
-     */
-    @Path("session-stats")
-    @GET
-    @NoCache
-    @Produces(MediaType.APPLICATION_JSON)
-    public SessionStats getSessionStats(@QueryParam("users") @DefaultValue("false") boolean users) {
-        logger.info("session-stats");
-        auth.requireView();
-        if (application.getManagementUrl() == null || application.getManagementUrl().trim().equals("")) {
-            logger.info("sending empty stats");
-            SessionStats stats = new SessionStats();
-            if (users) stats.setUsers(new HashMap<String, UserStats>());
-            return stats;
-        }
-        SessionStats stats = new ResourceAdminManager().getSessionStats(uriInfo.getRequestUri(), session, realm, application, users);
-        if (stats == null) {
-            logger.info("app returned null stats");
-        } else {
-            logger.info("activeUsers: " + stats.getActiveUsers());
-            logger.info("activeSessions: " + stats.getActiveSessions());
-        }
-        return stats;
-    }
-
-    /**
      * Number of user sessions associated with this application
      *
      * {
@@ -363,7 +331,7 @@ public class ApplicationResource {
     @POST
     public void logoutAll() {
         auth.requireManage();
-        new ResourceAdminManager().logoutApplication(uriInfo.getRequestUri(), realm, application, null, null);
+        new ResourceAdminManager().logoutApplication(uriInfo.getRequestUri(), realm, application, null);
     }
 
     /**
@@ -378,7 +346,9 @@ public class ApplicationResource {
         if (user == null) {
             throw new NotFoundException("User not found");
         }
-        new ResourceAdminManager().logoutApplication(uriInfo.getRequestUri(), realm, application, user.getId(), null);
+
+        List<UserSessionModel> userSessions = session.sessions().getUserSessions(realm, user);
+        new ResourceAdminManager().logoutApplication(uriInfo.getRequestUri(), realm, application, userSessions);
     }
 
 
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java b/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java
index 0f32533..b6ea102 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java
@@ -19,7 +19,6 @@ import org.keycloak.models.cache.CacheUserProvider;
 import org.keycloak.models.utils.ModelToRepresentation;
 import org.keycloak.models.utils.RepresentationToModel;
 import org.keycloak.protocol.oidc.TokenManager;
-import org.keycloak.representations.adapters.action.SessionStats;
 import org.keycloak.representations.idm.RealmEventsConfigRepresentation;
 import org.keycloak.representations.idm.RealmRepresentation;
 import org.keycloak.services.managers.LDAPConnectionTestManager;
@@ -284,28 +283,6 @@ public class RealmAdminResource {
     }
 
     /**
-     * Any application that has an admin URL will be asked directly how many sessions they have active and what users
-     * are involved with those sessions.
-     *
-     * @return
-     */
-    @Path("session-stats")
-    @GET
-    @NoCache
-    @Produces(MediaType.APPLICATION_JSON)
-    public Map<String, SessionStats> getSessionStats() {
-        logger.info("session-stats");
-        auth.requireView();
-        Map<String, SessionStats> stats = new HashMap<String, SessionStats>();
-        for (ApplicationModel applicationModel : realm.getApplications()) {
-            if (applicationModel.getManagementUrl() == null) continue;
-            SessionStats appStats = new ResourceAdminManager().getSessionStats(uriInfo.getRequestUri(), this.session, realm, applicationModel, false);
-            stats.put(applicationModel.getName(), appStats);
-        }
-        return stats;
-    }
-
-    /**
      * View the events provider and how it is configured.
      *
      * @return
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java b/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java
index d71391e..0873314 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java
@@ -24,7 +24,6 @@ import org.keycloak.models.utils.ModelToRepresentation;
 import org.keycloak.models.utils.RepresentationToModel;
 import org.keycloak.protocol.oidc.OpenIDConnect;
 import org.keycloak.protocol.oidc.TokenManager;
-import org.keycloak.representations.adapters.action.UserStats;
 import org.keycloak.representations.idm.ApplicationMappingsRepresentation;
 import org.keycloak.representations.idm.CredentialRepresentation;
 import org.keycloak.representations.idm.MappingsRepresentation;
@@ -218,36 +217,6 @@ public class UsersResource {
     }
 
     /**
-     * For each application with an admin URL, query them for the set of users logged in.  This not as reliable
-     * as getSessions().
-     *
-     * @See getSessions
-     *
-     * @param username
-     * @return
-     */
-    @Path("{username}/session-stats")
-    @GET
-    @NoCache
-    @Produces(MediaType.APPLICATION_JSON)
-    public Map<String, UserStats> getSessionStats(final @PathParam("username") String username) {
-        logger.info("session-stats");
-        auth.requireView();
-        UserModel user = session.users().getUserByUsername(username, realm);
-        if (user == null) {
-            throw new NotFoundException("User not found");
-        }
-        Map<String, UserStats> stats = new HashMap<String, UserStats>();
-        for (ApplicationModel applicationModel : realm.getApplications()) {
-            if (applicationModel.getManagementUrl() == null) continue;
-            UserStats appStats = new ResourceAdminManager().getUserStats(uriInfo.getRequestUri(), realm, applicationModel, user);
-            if (appStats == null) continue;
-            if (appStats.isLoggedIn()) stats.put(applicationModel.getName(), appStats);
-        }
-        return stats;
-    }
-
-    /**
      * List set of sessions associated with this user.
      *
      * @param username
@@ -258,7 +227,6 @@ public class UsersResource {
     @NoCache
     @Produces(MediaType.APPLICATION_JSON)
     public List<UserSessionRepresentation> getSessions(final @PathParam("username") String username) {
-        logger.info("sessions");
         auth.requireView();
         UserModel user = session.users().getUserByUsername(username, realm);
         if (user == null) {
@@ -345,8 +313,8 @@ public class UsersResource {
         if (user == null) {
             throw new NotFoundException("User not found");
         }
+        new ResourceAdminManager().logoutUser(uriInfo.getRequestUri(), realm, user, session);
         session.sessions().removeUserSessions(realm, user);
-        new ResourceAdminManager().logoutUser(uriInfo.getRequestUri(), realm, user.getId(), null);
     }
 
     /**
diff --git a/testsuite/docker-cluster/shared-files/deploy-examples.sh b/testsuite/docker-cluster/shared-files/deploy-examples.sh
index 10f9643..0778a3d 100644
--- a/testsuite/docker-cluster/shared-files/deploy-examples.sh
+++ b/testsuite/docker-cluster/shared-files/deploy-examples.sh
@@ -23,6 +23,10 @@ done;
 # Configure admin-access.war
 sed -i -e 's/false/true/' admin-access.war/WEB-INF/web.xml
 
+# Enforce refreshing token for product-portal and customer-portal war
+# sed -i -e 's/\"\/auth\",/&\n    \"always-refresh-token\": true,/' customer-portal.war/WEB-INF/keycloak.json;
+sed -i -e 's/\"\/auth\",/&\n    \"always-refresh-token\": true,/' product-portal.war/WEB-INF/keycloak.json;
+
 # Configure other examples
 for I in *.war/WEB-INF/keycloak.json; do
   sed -i -e 's/\"\/auth\",/&\n    \"auth-server-url-for-backend-requests\": \"http:\/\/\$\{jboss.host.name\}:8080\/auth\",/' $I;
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/AdapterTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/AdapterTest.java
index 28bd4b6..851a450 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/AdapterTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/AdapterTest.java
@@ -23,10 +23,8 @@ package org.keycloak.testsuite.adapter;
 
 import org.junit.Assert;
 import org.junit.ClassRule;
-import org.junit.FixMethodOrder;
 import org.junit.Rule;
 import org.junit.Test;
-import org.junit.runners.MethodSorters;
 import org.keycloak.Config;
 import org.keycloak.OAuth2Constants;
 import org.keycloak.Version;
@@ -40,7 +38,6 @@ import org.keycloak.models.UserSessionModel;
 import org.keycloak.protocol.oidc.OpenIDConnectService;
 import org.keycloak.protocol.oidc.TokenManager;
 import org.keycloak.representations.AccessToken;
-import org.keycloak.representations.adapters.action.SessionStats;
 import org.keycloak.representations.idm.RealmRepresentation;
 import org.keycloak.services.managers.RealmManager;
 import org.keycloak.services.managers.ResourceAdminManager;
@@ -158,17 +155,16 @@ public class AdapterTest {
         Client client = ClientBuilder.newClient();
         UriBuilder authBase = UriBuilder.fromUri("http://localhost:8081/auth");
         WebTarget adminTarget = client.target(AdminRoot.realmsUrl(authBase)).path("demo");
-        Map<String, SessionStats> stats = adminTarget.path("session-stats").request()
+        Map<String, Integer> stats = adminTarget.path("application-session-stats").request()
                 .header(HttpHeaders.AUTHORIZATION, "Bearer " + adminToken)
-                .get(new GenericType<Map<String, SessionStats>>() {
+                .get(new GenericType<Map<String, Integer>>() {
                 });
-
-        SessionStats custStats = stats.get("customer-portal");
-        Assert.assertNotNull(custStats);
-        Assert.assertEquals(1, custStats.getActiveSessions());
-        SessionStats prodStats = stats.get("product-portal");
-        Assert.assertNotNull(prodStats);
-        Assert.assertEquals(1, prodStats.getActiveSessions());
+        Integer custSessionsCount = stats.get("customer-portal");
+        Assert.assertNotNull(custSessionsCount);
+        Assert.assertTrue(1 == custSessionsCount);
+        Integer prodStatsCount = stats.get("product-portal");
+        Assert.assertNotNull(prodStatsCount);
+        Assert.assertTrue(1 == prodStatsCount);
 
         client.close();
 
@@ -299,7 +295,7 @@ public class AdapterTest {
         realm = session.realms().getRealmByName("demo");
         // need to cleanup so other tests don't fail, so invalidate http sessions on remote clients.
         UserModel user = session.users().getUserByUsername("bburke@redhat.com", realm);
-        new ResourceAdminManager().logoutUser(null, realm, user.getId(), null);
+        new ResourceAdminManager().logoutUser(null, realm, user, session);
         realm.setSsoSessionIdleTimeout(originalIdle);
         session.getTransaction().commit();
         session.close();