KeyCloak — Choosing the right Authentication Strategy

Rahul Aggarwal
Deutsche Telekom Digital Labs
6 min readFeb 6, 2024

Keycloak is a widely used open-source identity and access management solution that provides secure authentication capabilities with various authentication mechanisms which includes

  1. Public: Permits authentication, without a client secret.
  2. Confidential: Permits authentication, with a client secret.
  3. Bearer only: You need an access token to access its resources.

So, based on these clients' authentication methods we can divide the application into two parts from an authentication point of view

  • Web Browser-Based Login Authentication: For such an application, the user login to the browser and is authenticated using the public and confidential client of the keycloak
  • Bearer Token Based Authentication: This is required for service and service communication and Service A sends the bearer token to Service B , Service B then validates the token for its authenticity.

Spring Security based on above authentication methods provides different Session Registration Strategies

public class RegisterSessionAuthenticationStrategy implements SessionAuthenticationStrategy {
private final SessionRegistry sessionRegistry;

public RegisterSessionAuthenticationStrategy(SessionRegistry sessionRegistry) {
Assert.notNull(sessionRegistry, "The sessionRegistry cannot be null");
this.sessionRegistry = sessionRegistry;
}

public void onAuthentication(Authentication authentication, HttpServletRequest request, HttpServletResponse response) {
this.sessionRegistry.registerNewSession(request.getSession().getId(), authentication.getPrincipal());
}
}
  • NullAuthenticatedSessionStrategy: This Strategy should be used for bearer applications as per keycloak official documentation as this does not register a session for an individual request.

Choosing the right authentication strategy depending upon the client authentication mechanism is very important as it may lead to sleepless nights if wrongly configured

How it went wrong for us

In our case for one of the services PushDPS, we are using the Bearer token-based authentication flow where the client has to pass the access token as a bearer token while calling the authenticated APIs. As mentioned above for bearer token-based authentication we should be using NullSessionAuthenticationStrategy while declaring the session strategy bean rather we were using RegisterSessionAuthenticationStrategy which saves session token In-Memory of the respective application.

Problem Statement — Memory leaks in PushDPS leading to OOM under high traffic.

We identified that during high traffic we have memory leaks in Push DPS, Push DPS is a bearer. token-based authentication application where clients send a token generated by keylock, which gets validated at Push DPS using Keycloack Spring boot security adaptor and after successful validation request is routed to the respective Push DPS end point.

How we reached the cause with the memory dump

By taking memory dumps during the high traffic hours, we figured out that 67.5% of memory is being accumulated within the Concurrent HashMap consumed by Keycloak SessionRegistory.

of "org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy"loaded by "org.springframework.boot.loader.LaunchedURLClassLoader @ 0x7048d7488" occupies 50,91,65,872 (66.29%) bytes. The memory is accumulated in one instance of "java.util.concurrent.ConcurrentHashMap$Node[]" loaded by "<system class loader>".

Keywords
org.springframework.boot.loader.LaunchedURLClassLoader @ 0x7048d7488
java.util.concurrent.ConcurrentHashMap$Node[]
org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy
Memory Leaks in Application

More Insights

To further dig down we performed a load test with 300 users, a ramp-up time of 50 sec and running in the loop for 20 minutes

Memory & CPU Utilisation Graphs with Different Authentication Strategy

  1. Memory usage trend with RegisterSessionAuthenticationStrategy
Memory Usage RegisterSessionAuthenticationStrategy

2. CPU usage trend with RegisterSessionAuthenticationStrategy

CPU Usage RegisterSessionAuthenticationStrategy

3. Memory usage trend with NullAuthenticatedSessionStrategy

Memory usage NullAuthenticatedSessionStrategy

4. CPU usage trend with NullAuthenticatedSessionStrategy

CPU usage NullAuthenticatedSessionStrategy

Conclusion

  1. Memory usage with RegisterSessionAuthenticationStrategy is pretty high i.e up to 3.5GB and is occupied further after jmeter script is finished whereas for NullAuthenticatedSessionStrategy max memory usage during the script run was up to 1.5 GB and post script run memory came to its normal state i.e 200 MB
  2. CPU Utilisation with RegisterSessionAuthenticationStrategy has reached up to 85% whereas with NullAuthenticatedSessionStrategy it
    reached up to 25–30%

Doubts Raised & Clarifications

Question:

Since after migration to NullAuthenticatedSessionStrategy from RegisterSessionAuthenticationStrategy, we won’t be storing session tokens and then for every incoming request the application has to introspect token and this will increase traffic on Keycloak

Answer:
A bearer token-based authentication application does not call Keycloak for every incoming request it validates the token with the public key stored as part of the Keycloak spring adaptor injected as a maven dependency in the application

  • For bearer flow: token validation is done using the public key
  • Keycloack spring adaptor which is part of the application stores a public key and a kid in an in-memory cache for a time of 1 day (86400 sec) which is configurable by public-key-cache-ttl
    as per keycloak documentation https://www.keycloak.org/docs/4.8/securing_apps/
public-key-cache-ttl
Amount of time, in seconds, specifying maximum interval between two requests to Keycloak to retrieve new public keys. It is 86400 seconds (1 day) by default. Adapter will always try to download new public key when it recognize token with unknown kid . If it recognize token with known kid, it will just use the public key downloaded previously. However at least once per this configured interval (1 day by default) will be new public key always downloaded even if the kid of token is already known.

So to conclude this further, there are two validation flows involved for token authenticity

  • Microservice to Keycloack (Online): Where the token is validated using keycloak introspect endpoint and a request is sent to Keycloak to validate the token, this is costly as it involves a round-trip
  • Microservice validating token from Cache (Offline): Token is validated using the PublicKeyValidator which validates the token using the public key stored in the cache for a default time of 1 day

Reference Links:

--

--

No responses yet