2
votes

I am using Keycloak 3.4 in a Java Application using Spring Framework and Jetty 8.1 with Keycloak Jetty-81-Adapter 3.4.

According to the Keycloak documentation I should be able to use the HttpServletRequest in a Java EE application to logout from Keycloak. However, this does not work in my case, even though Jetty supports HttpServletRequests.

You can log out of a web application in multiple ways. For Java EE servlet containers, you can call HttpServletRequest.logout()..

If I try to logout this way, I get redirected to keycloak (login screen with option to choose from multiple realm logins). When I choose my preferred realm however, I am immediately logged in to the webapplication again, without having to provide any credentials.

I tried the alternative approach, by redirecting to Keycloak:

For other browser applications, you can redirect the browser to
http://auth-server/auth/realms/{realm-name}/protocol/openid-connect/logout?redirect_uri=encodedRedirectUri

but it throws a connection refused error in the Keycloak log, because Keycloak tries to call my webapp in a direct way. It has no effect on the Keycloak session, which stays active. I strongly prefer no serverside calls necessary from Keycloak to the webapp directly.

Any suggestions why the HttpServletRequest.logout() does not destroy the keycloak session in my case? Is the Jetty implementation of the HttpServletRequest so different from the Java EE implementation that it could not work at all?

3

3 Answers

8
votes

I have had a similar experience when using a remote (OIDC) identity provider. What I found was that the HttpServletRequest.logout did actually destroy the session in Keycloak, but did not propagate to the logout url of my remote identity provider. When going to the remote login-site, it just immediatly redirected me back, seeing that I had an active session. This looked a lot like the keycloak session wasn't actually invalidated, but I checked and it was. Using a browser redirect to the url did logout on both places. Might be a bug in Keycloak.

Could it be that you are facing the same problem? To verify, try logging out, then select your client in keycloak and list sessions, to see whether it still exists in Keycloak.

1
votes

You need to put the Servlet or the Rest that contains the "request.logout()" action as a protected resource, so that the token would be available:

Check out the below documentation: "

server passing the refresh token. If the method is executed from an unprotected page (a page that does not check for a valid token) the refresh token can be unavailable and, in that case, the adapter skips the call. For this reason, using a protected page to execute HttpServletRequest.logout() is recommended so that current tokens are always taken into account and an interaction with the {project_name} server is performed if needed.

"

1
votes

If the method (logout) is executed from an unprotected page (a page that does not check for a valid token) the refresh token can be unavailable and, in that case, the adapter skips the call. For this reason, using a protected page to execute HttpServletRequest.logout() is recommended so that current tokens are always taken into account and an interaction with the Keycloak server is performed if needed. https://www.keycloak.org/docs/latest/securing_apps/index.html#logout

This worked for me in an protected page, but dont work in an unprotected page

public ExternalContext currentExternalContext() {
        if (FacesContext.getCurrentInstance() == null) {
            throw new RuntimeException("message here ");
        } else {
            return FacesContext.getCurrentInstance().getExternalContext();
         }
    }

public void logout() throws IOException, ServletException {
    HttpServletRequest request = (HttpServletRequest) currentExternalContext().getRequest();
    ExternalContext externalContext = currentExternalContext();
    request.logout();
    externalContext.redirect(externalContext.getRequestContextPath());
}