Backend Development 9 min read

Combining JWT and Session for Secure User Authentication

This article explains how JWT provides stateless user authentication while Session adds an extra security layer and state management, detailing their individual roles, reasons for using Session, combined benefits, and includes Java code examples for implementing login and token validation.

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

In this article, a senior architect discusses the use of JWT for user authentication and how Session can serve as an auxiliary mechanism.

Role of JWT

User Authentication: JWT carries user identity and permissions, allowing the server to verify the user on each request.

Statelessness: JWT does not require server‑side session storage, enabling horizontal scaling and load balancing.

Role of Session

Additional Security Layer: Session provides a safeguard against token leakage or misuse by ensuring the token also exists in the server’s session store.

Token Lifecycle Management: Session makes it easy to force re‑login, manually revoke tokens, or handle logout.

"Remember Me" Support: When users opt for "remember me," Session tracks the state and decides whether an expired JWT can still be used.

Why Create a Session

Prevent Token Abuse: Server‑side Session verification ensures that even a valid token must correspond to an authenticated session.

Support User‑Initiated Logout: Deleting the Session record instantly invalidates the token.

Fine‑Grained Control: Session enables precise permission control, forced offline, and session expiration handling.

State Tracking: Session can record user activity, login history, and other metrics.

Combined Advantages

Stateless Authentication: JWT allows the system to scale horizontally without storing session data.

State Management & Security: Session adds stateful control and extra security, ensuring token usage is safe and reliable.

Code Example

The following Java snippets demonstrate creating a JWT and a Session during login, and validating the token with Session checks.

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);
}

@Override
public DefaultJwtPayload validateToken(String token) throws AuthException {
    try {
        // 1. Validate JWT token 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. Check if session contains this token
        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 acts as an auxiliary mechanism that adds extra security and state management; combining them leverages the strengths of both to build a highly extensible yet securely controlled system.

backendSecurityAuthenticationJWTsession
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.