Information Security 7 min read

Combining JWT and Session for Secure Authentication and State Management

This article explains how JWT provides stateless user authentication while Session adds an extra security layer and state management, detailing their respective roles, the reasons for using Session alongside JWT, and offering Java code examples that illustrate their combined implementation.

Architecture Digest
Architecture Digest
Architecture Digest
Combining JWT and Session for Secure Authentication and State Management

JWT Role

JWT contains user identity and permission information, enabling the client to send the token with each request for the server to verify the user's identity. Because JWT does not require server‑side storage of session data, it allows the server to remain stateless, facilitating horizontal scaling and load balancing.

Session Role

Session acts as an additional security layer, ensuring that even if a JWT is valid, a corresponding server‑side session must exist. It also simplifies token lifecycle management (e.g., forced re‑login, manual revocation) and supports "remember me" functionality by tracking the user's choice and deciding whether an expired JWT can still be used.

Why Create a Session

Prevent token abuse: Server‑side session verification guarantees that a token is only usable if the server has authenticated the session.

Support user‑initiated logout: Deleting the server‑side session invalidates the token even before its expiration.

Fine‑grained control: Sessions enable precise permission handling, forced offline, and custom session timeout policies.

State tracking: Sessions allow monitoring of user activity, login history, and other stateful information.

Advantages of Combining JWT and Session

Using JWT provides stateless authentication, which is ideal for scaling, while Session supplies additional state management and security, ensuring token usage is tightly controlled and allowing features such as logout and "remember me".

Code Example

The following Java code demonstrates how to generate a JWT during login, create a corresponding session, and validate the token together with the session.

public LoginResponse login(String username, String password) throws AuthException {
    // Verify username and password
    User user = userService.authenticate(username, password);
    if (user == null) {
        throw new AuthException("Invalid username or password");
    }
    // Generate JWT Token
    String token = createJwt(user.getId(), user.getRoles());
    // Create session
    sessionManagerApi.createSession(token, user);
    // Return Token
    return new LoginResponse(token);
}

public void createSession(String token, User user) {
    LoginUser loginUser = new LoginUser();
    loginUser.setToken(token);
    loginUser.setUserId(user.getId());
    loginUser.setRoles(user.getRoles());
    sessionManagerApi.saveSession(token, loginUser);
}

During request validation, the JWT is first checked for integrity, then the existence of a matching session is verified.

@Override
public DefaultJwtPayload validateToken(String token) throws AuthException {
    try {
        // 1. Validate JWT itself
        JwtContext.me().validateTokenWithException(token);
        // 2. Retrieve JWT payload
        DefaultJwtPayload defaultPayload = JwtContext.me().getDefaultPayload(token);
        // 3. If "remember me" is enabled, skip session check
        if (defaultPayload.getRememberMe()) {
            return defaultPayload;
        }
        // 4. Verify session existence
        LoginUser session = sessionManagerApi.getSession(token);
        if (session == null) {
            throw new AuthException(AUTH_EXPIRED_ERROR);
        }
        return defaultPayload;
    } catch (JwtException jwtException) {
        if (JwtExceptionEnum.JWT_EXPIRED_ERROR.getErrorCode().equals(jwtException.getErrorCode())) {
            throw new AuthException(AUTH_EXPIRED_ERROR);
        } else {
            throw new AuthException(TOKEN_PARSE_ERROR);
        }
    } catch (io.jsonwebtoken.JwtException jwtSelfException) {
        throw new AuthException(TOKEN_PARSE_ERROR);
    }
}

Conclusion

In this scenario, JWT provides lightweight, stateless authentication, while Session supplies additional security and state management. Combining the two leverages the scalability of JWT and the fine‑grained control of Session, resulting in a robust and secure authentication system.

backendJavaSecurityAuthenticationJWTsession
Architecture Digest
Written by

Architecture Digest

Focusing on Java backend development, covering application architecture from top-tier internet companies (high availability, high performance, high stability), big data, machine learning, Java architecture, and other popular fields.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.