Backend Development 9 min read

Combining JWT and Session for Secure User Authentication

This article explains the distinct roles of JWT and Session in user authentication, why a Session layer is needed alongside JWT, and demonstrates with Java code how to create and validate tokens while managing session state for enhanced security and scalability.

Top Architect
Top Architect
Top Architect
Combining JWT and Session for Secure User Authentication

In modern web applications, JWT is used for stateless user authentication, while Session can provide an auxiliary security layer and state management.

JWT Role

User Authentication: JWT carries user identity and permissions; the client sends it with each request and the server validates it to confirm the user.

Statelessness: No server‑side session storage is required, enabling easy horizontal scaling and load balancing.

Session Role

Additional Security Layer: Even if a JWT is valid, the request must correspond to an existing server‑side session, protecting against token leakage or misuse.

Token Lifecycle Management: Sessions allow forced re‑login, manual token revocation, and other lifecycle controls.

"Remember Me" Support: When users choose to be remembered, the session records this state and decides whether an expired JWT can still be used.

Why Create a Session

Prevent Token Abuse: Server‑side session verification ensures that a valid token is also authenticated by the server.

Support User Logout: Deleting the server‑side session instantly invalidates the token, even if it has not expired.

Fine‑grained Control: Sessions enable precise permission control, forced offline, and custom session expiration.

Status Tracking: Sessions can store user activity, login history, and other monitoring data.

Advantages of Combining JWT and Session

Stateless Authentication: JWT provides a lightweight, stateless authentication mechanism suitable for scaling.

State Management & Security: Session adds stateful security checks, ensuring token usage is safe and controlled.

Code Example

The following simplified Java code shows how to generate a JWT during login and create a corresponding session.

public LoginResponse login(String username, String password) throws AuthException {
    // Validate 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 system first checks the JWT and then verifies the existence of a matching session.

@Override
public DefaultJwtPayload validateToken(String token) throws AuthException {
    try {
        // 1. Validate JWT itself
        JwtContext.me().validateTokenWithException(token);
        // 2. Get 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 stateless authentication for scalability, while Session adds an extra security layer and state management; together they combine the benefits of both approaches, ensuring a highly extensible system with fine‑grained security control.

backendJavaSecurityAuthenticationJWTsession
Top Architect
Written by

Top Architect

Top Architect focuses on sharing practical architecture knowledge, covering enterprise, system, website, large‑scale distributed, and high‑availability architectures, plus architecture adjustments using internet technologies. We welcome idea‑driven, sharing‑oriented architects to exchange and learn together.

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.