Access Token Refresh Mechanism in Keycloak: Implementing Seamless User Session Persistence Using Refresh Tokens

Dec 08, 2025 · Programming · 9 views · 7.8

Keywords: Keycloak | access token refresh | OAuth 2.0 | vert.x | authentication

Abstract: This paper provides an in-depth exploration of how to leverage the refresh token mechanism in Keycloak to automatically refresh access tokens, thereby maintaining continuous user sessions. It begins by analyzing the core concepts and lifecycle management of access tokens and refresh tokens within the OAuth 2.0 protocol. The paper then details the specific methods for implementing token refresh through Keycloak's REST API, including request endpoints, parameter formats, and response handling. Practical code examples demonstrate how to integrate the vertx-auth component within the vert.x framework to call Keycloak's token refresh interface, while also discussing key implementation aspects such as token expiration, security policies, and error handling. Finally, the paper compares the advantages and disadvantages of different implementation approaches, offering comprehensive technical guidance for developers.

Introduction and Background

In modern distributed systems and microservices architectures, identity authentication and authorization mechanisms are core components ensuring system security. The OAuth 2.0 protocol, as an industry standard, balances security and user experience through the separation of access tokens (access_token) and refresh tokens (refresh_token). Access tokens typically have short lifespans (e.g., minutes to hours) to protect API resource access, while refresh tokens have longer lifespans (e.g., days to months) to obtain new access tokens when the current ones expire, thus avoiding frequent user re-authentication.

Keycloak, as an open-source identity and access management solution, fully supports the OAuth 2.0 protocol and provides extensive REST API interfaces. In practical applications, when a user's access token expires, the system needs to automatically use the refresh token to obtain a new access token, maintaining session continuity. This is not only crucial for enhancing user experience but also aligns with security best practices.

Detailed Explanation of Keycloak Token Refresh Mechanism

Keycloak supports refresh token operations through the standard OAuth 2.0 token endpoint, located at https://keycloak.example.com/auth/realms/myrealm/protocol/openid-connect/token, where myrealm should be replaced with the actual realm name. Refresh token requests must use the HTTP POST method with the request body encoded in application/x-www-form-urlencoded format.

The request must include the following key parameters:

Below is a complete request example:

POST /auth/realms/myrealm/protocol/openid-connect/token HTTP/1.1
Host: keycloak.example.com
Content-Type: application/x-www-form-urlencoded

client_id=my-client-name&grant_type=refresh_token&refresh_token=eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJwM2...

A successful response returns a new access token, optionally a new refresh token, and other related metadata, typically in JSON format:

{
  "access_token": "new_access_token_value",
  "expires_in": 300,
  "refresh_expires_in": 1800,
  "refresh_token": "new_refresh_token_value",
  "token_type": "Bearer",
  "id_token": "optional_id_token_value"
}

If the refresh token is expired or invalid, Keycloak returns an HTTP 400 error, at which point the user should be redirected to re-authenticate.

Implementation in the vert.x Framework

In vert.x-based applications, token refresh can be implemented using the vertx-auth component or by directly calling the Keycloak REST API. The following code example using vertx-auth demonstrates how to integrate refresh logic:

import io.vertx.core.Vertx;
import io.vertx.ext.auth.oauth2.OAuth2Auth;
import io.vertx.ext.auth.oauth2.OAuth2FlowType;
import io.vertx.ext.auth.oauth2.providers.KeycloakAuth;

public class TokenRefreshExample {
    public static void main(String[] args) {
        Vertx vertx = Vertx.vertx();
        
        // Configure Keycloak authentication provider
        OAuth2Auth oauth2 = KeycloakAuth.create(vertx, OAuth2FlowType.PASSWORD, config -> {
            config.setSite("https://keycloak.example.com/auth")
                  .setClientId("my-client-name")
                  .setRealm("myrealm");
        });
        
        // Simulate initial authentication to obtain tokens
        oauth2.authenticate(new JsonObject()
            .put("username", "user")
            .put("password", "password"), authResult -> {
                if (authResult.succeeded()) {
                    User user = authResult.result();
                    String accessToken = user.principal().getString("access_token");
                    String refreshToken = user.principal().getString("refresh_token");
                    
                    // Periodically check and refresh access token
                    vertx.setPeriodic(60000, timerId -> {
                        if (isTokenExpired(accessToken)) {
                            refreshAccessToken(oauth2, refreshToken, newRefreshResult -> {
                                if (newRefreshResult.succeeded()) {
                                    // Update tokens in user session
                                    updateUserTokens(user, newRefreshResult.result());
                                } else {
                                    // Handle refresh failure, e.g., redirect to login
                                    handleRefreshFailure(newRefreshResult.cause());
                                }
                            });
                        }
                    });
                }
            });
    }
    
    private static void refreshAccessToken(OAuth2Auth oauth2, String refreshToken, Handler<AsyncResult<JsonObject>> handler) {
        // Use vertx-auth built-in method to refresh token
        oauth2.refreshToken(refreshToken, handler);
    }
    
    private static boolean isTokenExpired(String token) {
        // Parse JWT token and check expiration time
        // Implementation details omitted
        return false;
    }
}

As an alternative, the vert.x HTTP client can be used to directly call the Keycloak REST API:

import io.vertx.core.Vertx;
import io.vertx.core.buffer.Buffer;
import io.vertx.ext.web.client.WebClient;

public class DirectApiRefreshExample {
    public static void main(String[] args) {
        Vertx vertx = Vertx.vertx();
        WebClient client = WebClient.create(vertx);
        
        String refreshToken = "existing_refresh_token";
        String requestBody = "client_id=my-client-name&grant_type=refresh_token&refresh_token=" + refreshToken;
        
        client.postAbs("https://keycloak.example.com/auth/realms/myrealm/protocol/openid-connect/token")
            .putHeader("Content-Type", "application/x-www-form-urlencoded")
            .sendBuffer(Buffer.buffer(requestBody), response -> {
                if (response.succeeded()) {
                    JsonObject tokens = response.result().bodyAsJsonObject();
                    String newAccessToken = tokens.getString("access_token");
                    // Process new access token
                } else {
                    // Handle error response
                }
            });
    }
}

Security Considerations and Best Practices

When implementing token refresh mechanisms, the following security factors must be considered:

  1. Token Storage Security: Refresh tokens should be stored securely, avoiding exposure to client-side JavaScript. It is recommended to use HTTP-only cookies or secure local storage mechanisms.
  2. Refresh Token Rotation: Keycloak supports refresh token rotation policies, where each refresh operation may return a new refresh token. Applications should promptly update stored refresh tokens to prevent reuse of old tokens.
  3. Error Handling: When a refresh token expires or is invalid, HTTP 400 errors should be handled appropriately, such as clearing user sessions and redirecting to the login page.
  4. Network Transmission Security: All token-related requests must be transmitted over HTTPS to prevent man-in-the-middle attacks.

Additionally, appropriate monitoring and logging should be implemented to detect abnormal refresh patterns, which may indicate security attacks.

Performance Optimization and Scalability

In high-concurrency scenarios, token refresh operations can become performance bottlenecks. The following optimization strategies are recommended:

Conclusion

Through Keycloak's refresh token mechanism, developers can effectively implement user session persistence, enhancing user experience while maintaining system security. Whether using the vertx-auth component or directly calling REST APIs, a deep understanding of the OAuth 2.0 protocol specifications and adherence to security best practices are essential. The technical details and code examples provided in this paper offer comprehensive guidance for implementing this functionality in real-world projects, allowing developers to choose the most suitable approach based on specific requirements.

Copyright Notice: All rights in this article are reserved by the operators of DevGex. Reasonable sharing and citation are welcome; any reproduction, excerpting, or re-publication without prior permission is prohibited.