Information Security 7 min read

Combining JWT and Session for Secure User Authentication and Authorization

This article explains the complementary roles of JWT and server‑side Session in user authentication and authorization, outlines why Session is needed for added security and lifecycle management, and provides Java code examples demonstrating their integrated usage.

Java Architect Essentials
Java Architect Essentials
Java Architect Essentials
Combining JWT and Session for Secure User Authentication and Authorization

Using JWT for user authentication and authorization, while Session plays an auxiliary role, offers a balanced approach that leverages the strengths of both mechanisms.

JWT's Role

User Authentication: JWT carries identity and permission information; 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 horizontal scaling and load balancing.

Session's Role

Additional Security Layer: Session adds protection against token leakage or misuse by requiring a corresponding server‑side session.

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

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

Why Create a Session

Although JWT works in a stateless environment, introducing Session brings several benefits:

Prevent Token Abuse: Server‑side verification ensures that a valid token must also be associated with an authenticated session.

Support User Logout: Deleting the server‑side Session invalidates the token even before its expiration.

Fine‑Grained Control: Enables forced offline, session timeout, and detailed permission handling.

State Tracking: Allows monitoring of user activity, login history, and other stateful information.

Advantages of Combining JWT and Session

By using both, systems achieve both scalability and enhanced security:

Stateless Authentication: JWT provides lightweight, stateless authentication suitable for distributed systems.

State Management & Security: Session supplies additional state tracking and safeguards, ensuring token usage is tightly controlled.

Code Example

Below is a simplified Java example showing how to create a JWT and a Session during user login:

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 JWT is first verified, then the corresponding Session is checked:

@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. 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, scalable authentication, while Session adds an extra security layer and state management; together they ensure high extensibility and fine‑grained security control.

backendsecurityAuthenticationJWTauthorizationsession
Java Architect Essentials
Written by

Java Architect Essentials

Committed to sharing quality articles and tutorials to help Java programmers progress from junior to mid-level to senior architect. We curate high-quality learning resources, interview questions, videos, and projects from across the internet to help you systematically improve your Java architecture skills. Follow and reply '1024' to get Java programming resources. Learn together, grow 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.