Transient sessions in Keycloak or how to save your cache performances ! Keycloak genrates a session on each user login and those sessions are replicated in Infinspan caches. Sometimes, you only need a token, not a session. In this article we will try to explain how to do it !

Introduction

Keycloak is an identity provider that supports openid connect, SAML and Docker V2 protocols. It is highly customizable and scalable. Its architecture is based on Quarkus (previously on Jboss) with a relational database and an embedded Infinispan cache (transactional cache). Infinispan can replicate or distribute caches on a cluster, by using jgroups.

With Keycloak deployed on a cluster with load balancing, all user sessions are replicated on all nodes.

Cache replication can consume resources (RAM, CPU, network) and sometimes we do not need a session but only a JWT token. Keycloak has introduced « transient sessions ».

This article explains why and how to use it.

Concept of sessions in Keycloak

https://www.keycloak.org/docs/latest/server_admin/#managing-user-sessions

A session is attached to a user and the client used to log in. From the session, access token and refresh token are forged. The « session_state » field in those tokens is the id of the session.

This session is stored in an infinispan cache, with other data such as users, client sessions… We will write a blog post about caches structure.

Distributed caches contain data, local cache are present only for performance by caching data from the relational database.

Distributed and replicated caches use Jgroups for replication around the cluster.

More : https://www.keycloak.org/server/caching

Limits

Creating a huge number of sessions could have some impacts on performances. Each infinispan node has to synchronize its data to the others. Usually, distributed caches are used for sessions.

https://infinispan.org/docs/stable/titles/configuring/configuring.html#distributed-caches_clustered-caches

distributed caches are not linearizable. For transactional caches, they do not support serialization/snapshot isolation.

For some types of operation, with automated operations, we can have some issues with inconsistency around the cluster. IE : login with direct access grant and after a token introspection or a refresh, on another node in the cluster, can result in an error.

Keycloak generates JWT tokens as Access Tokens and Refresh Tokens. Regarding to the RFCs, only id tokens (from openid connect, an extension to oauth2) have to be JWT. For convenience reasons, we often use Keycloak as a JWT generator (with powerful authentication and user management features).

Use only JWT tokens

For some use cases, having a JWT token is enough for authentication. It can have enough data into, without any need of userinfo or token introspection. For this use case, managing a session on Keycloak is useless.

If your application (backend and frontend) never use :

  • refresh token
  • user info
  • token instrospect

You can use a transient session.

Principle

https://www.keycloak.org/docs/latest/serveradmin/#transient-session

You can conduct transient sessions in Keycloak. When using transient sessions, Keycloak does not create a user session after successful authentication. Keycloak creates a temporary, transient session for the scope of the current request that successfully authenticates the user. Keycloak can run protocol mappers using transient sessions after authentication.

During transient sessions, the client application cannot refresh tokens, introspect tokens, or validate a specific session. Sometimes these actions are unnecessary, so you can avoid the additional resource use of persisting user sessions. This session saves performance, memory, and network communication (in cluster and cross-data center environments) resources.

It means that only an access token is forged, without a session behind.

Using a local installation of Keycloak, you will never see any difference in performance. On a replicated cluster that will save a lot of CPU time and network bandwidth.

Create an authenticator to use transient session

There is no option on client configuration to use transient sessions. It is done with a « client note » during the authentication process.

Find it in the documentation ? Of course no 🙁 …

So, take a look at the Authentication Processor :

https://github.com/keycloak/keycloak/blob/main/services/src/main/java/org/keycloak/authentication/AuthenticationProcessor.java#L1071

This is how we discover how to do it : with a client note AuthenticationManager.USERSESSIONPERSISTENT_STATE.

Constants are in : https://github.com/keycloak/keycloak/blob/main/server-spi/src/main/java/org/keycloak/models/UserSessionModel.java#L122

To use a client note, we have to implement our own Authenticator, so… let’s do it.

Create an AuthenticatorFactory, nothing special, only an implementation of AuthenticatorFactory with custom id, category and help text.

And an authenticator that only adds a client note :

public class TransientAuthenticator implements Authenticator {

    @Override
    public synchronized void authenticate(AuthenticationFlowContext context) {
        context.getAuthenticationSession().setClientNote(AuthenticationManager.USER_SESSION_PERSISTENT_STATE, UserSessionModel.SessionPersistenceState.TRANSIENT.toString());
        context.success();
        return;
    }

    @Override
    public void action(AuthenticationFlowContext context) { }

    @Override
    public boolean requiresUser() {
        return false;
    }

    @Override
    public boolean configuredFor(KeycloakSession session, RealmModel realm, UserModel user) {
        return false;
    }

    @Override
    public void setRequiredActions(KeycloakSession session, RealmModel realm, UserModel user) { }

    @Override
    public void close() {}
}

Only the line « setClientNote » is necessary to enable transient sessions.

Of course, you can do it on your own existing authenticator but having this dedicated authenticator for transient sessions makes it reusable.

Deploy

Go to « Authentication », then duplicate the « browser » (or « direct grant ») flow.

Click on « Add execution », then add the custom authenticator :

Enable it, put it on top :

Then, you have 2 choices :

  • set this flow as default for your realm (not recommended)
  • set the flow for a client that will need transient sessions

Any token retrieved by using this flow will not be usable for user info, token introspect or refresh token operations ! But this can save your cluster resources.

Mathieu PASSENAUD
Les derniers articles par Mathieu PASSENAUD (tout voir)