CodeGym /Courses /Module 5. Spring /Session and Token Handling

Session and Token Handling

Module 5. Spring
Level 17 , Lesson 8
Available

If you've worked with web apps, you've probably run into the term "session". A session is a mechanism that lets the server "remember" a user across requests. This is critical for authentication — otherwise you'd have to type your login and password on every click.

How does a session work? When a user authenticates, the server creates a unique identifier (Session ID). That identifier is sent to the client (for example, the browser), usually as a cookie. On each subsequent request the client attaches that identifier, which lets the server know who the user is.


Session management in Spring Security

Spring Security has powerful features for handling sessions. Let's look at how to configure and manage them.

Session policy configuration

One of the first tasks you'll meet is configuring the session management policy. For example, you can decide how many active sessions a single user can have. For that you can use the sessionManagement() and maximumSessions() methods.

Example:


@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .sessionManagement()
                .maximumSessions(1) // Only one session per user
                .maxSessionsPreventsLogin(true); // Prevent login when limit is exceeded
    }
}

Here we limited a user to one active session. If they try to log in from another device, they'll be denied.

Handling session termination

Spring Security lets you configure what happens when a session ends (for example, if the session expires or is terminated manually). You can use the SessionRegistry interface for that.

A logout handler might look like this:


@Component
public class CustomLogoutHandler implements LogoutHandler {

    @Override
    public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
        System.out.println("Session ended: " + authentication.getName());
    }
}

Session storage

Sessions can be stored either in server memory or in a database. Using a database is common in distributed systems where a load balancer might route a user to different servers between requests. In such cases sessions need to be "shared".


Security tokens: why sessions aren't enough?

In the era of microservices and REST API, tokens take the spotlight. Tokens are compact strings that represent some information (for example, a user identifier). Unlike sessions, tokens don't require server-side storage.

Advantages of tokens

  1. Server-state independence: tokens are stored on the client, which makes scaling apps easier.
  2. Reduced load: the server doesn't need to keep state for every user.
  3. API friendliness: tokens can be sent in an HTTP request header, which is ideal for REST APIs.

JWT (JSON Web Token)

JWT is a popular token format that is basically an encoded JSON string. Each token consists of three parts:

  1. Header (header): the token type and the encryption algorithm used.
  2. Payload (payload): the token data, e.g. userId or role.
  3. Signature (signature): protects the token from tampering.

Example JWT token:


eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJyb2xlIjoiVVNFUiJ9.abc123signature

Using JWT in Spring Security

Let's add JWT to our app's security.

To generate tokens you'll need a library, for example io.jsonwebtoken (JWT). Here's an example of creating a token:


import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.util.Date;

public class JwtTokenUtil {

    private static final String SECRET_KEY = "mySecretKey";

    public String generateToken(String username) {
        return Jwts.builder()
                .setSubject(username)
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis() + 86400000)) // 1 day
                .signWith(SignatureAlgorithm.HS256, SECRET_KEY)
                .compact();
    }
}

Validating tokens

Before using a token, make sure it's genuine and not expired. You need to decode it and verify its signature:


import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.Claims;

public class JwtTokenUtil {

    private static final String SECRET_KEY = "mySecretKey";

    public Claims validateToken(String token) {
        return Jwts.parser()
                .setSigningKey(SECRET_KEY)
                .parseClaimsJws(token)
                .getBody();
    }
}

The validateToken() method returns the token's payload if it's valid.


Setting up JWT authentication

Now let's integrate JWT into Spring Security. We'll create a filter for that:


@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {

    @Autowired
    private JwtTokenUtil jwtTokenUtil;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {

        String token = request.getHeader("Authorization");
        if (token != null && token.startsWith("Bearer ")) {
            token = token.substring(7); // Remove "Bearer "
            Claims claims = jwtTokenUtil.validateToken(token);
            if (claims != null) {
                String username = claims.getSubject();
                // Create authentication object
                UsernamePasswordAuthenticationToken auth =
                        new UsernamePasswordAuthenticationToken(username, null, Collections.emptyList());
                SecurityContextHolder.getContext().setAuthentication(auth);
            }
        }
        filterChain.doFilter(request, response);
    }
}

The filter checks the token before the request goes further.


Example of using tokens in our app

We created a REST API for authentication. The /login controller returns a JWT token. The client should send this token in the Authorization header on subsequent requests.

Controller:


@RestController
public class AuthController {

    @Autowired
    private JwtTokenUtil jwtTokenUtil;

    @PostMapping("/login")
    public ResponseEntity<?> login(@RequestParam String username, @RequestParam String password) {
        // Here you would typically check the username/password
        String token = jwtTokenUtil.generateToken(username);
        return ResponseEntity.ok(new HashMap<String, String>() {{
            put("token", token);
        }});
    }
}

Now your client can make an authorized request:


curl -H "Authorization: Bearer <your_token>" http://localhost:8080/protected/resource

When to use sessions and when to use tokens?

If you're working with traditional web applications, sessions are still a great choice. They're simple, convenient, and well integrated into the Spring ecosystem.

However, for REST APIs and microservices sessions are less convenient. Tokens, especially JWT, take the lead here — they offer mobility, easier scaling, and server-state independence.


Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION