Implementing JWT Authentication in Spring Boot Applications

Welcome, Java developers! In this post, we’ll dive into how to implement JWT (JSON Web Token) authentication in your Spring Boot applications. JWT is widely used for securing APIs by allowing you to verify the identity of users without needing to send their credentials with every request.

What is JWT?

JWT is a compact, URL-safe means of representing claims to be transferred between two parties. It consists of three parts: a header, a payload, and a signature. This allows you to create a token that can be shared between a client and a server, ensuring secure communication.

Why Use JWT for Authentication?

  • Stateless: JWTs are self-contained and do not require a server-side session, which fits well with microservices architecture.
  • Compact: The token is smaller than traditional session IDs, making it suitable for mobile app integration.
  • Supports Multiple Authentication Methods: Works seamlessly with OAuth2 for token-based authentication where users prove their identity.

Setting Up JWT Authentication in Spring Boot

Let’s implement JWT in a Spring Boot application.

Step 1: Add Dependencies

Add the necessary dependencies in your pom.xml:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.9.1</version>
</dependency>

Step 2: Configure Spring Security

Create a security configuration class:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
            .authorizeRequests()
            .antMatchers("/auth/**").permitAll()
            .anyRequest().authenticated();
        http.addFilterBefore(new JwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
    }
}

This configuration allows public access to the authentication endpoints while securing other routes.

Step 3: Create JWT Utility Class

Implement a utility class for generating and validating JWT tokens:

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Component
public class JwtUtil {

    private String secretKey = "your_secret_key";
    private long validityDuration = 1000 * 60 * 60; // 1 hour

    public String generateToken(String username) {
        Map<String, Object> claims = new HashMap<>();
        return createToken(claims, username);
    }

    private String createToken(Map<String, Object> claims, String subject) {
        return Jwts.builder()
            .setClaims(claims)
            .setSubject(subject)
            .setIssuedAt(new Date(System.currentTimeMillis()))
            .setExpiration(new Date(System.currentTimeMillis() + validityDuration))
            .signWith(SignatureAlgorithm.HS256, secretKey)
            .compact();
    }

    public Boolean validateToken(String token, String username) {
        final String extractedUsername = extractUsername(token);
        return (extractedUsername.equals(username) && !isTokenExpired(token));
    }

    private String extractUsername(String token) {
        return extractAllClaims(token).getSubject();
    }

    private Claims extractAllClaims(String token) {
        return Jwts.parser()
            .setSigningKey(secretKey)
            .parseClaimsJws(token)
            .getBody();
    }

    private Boolean isTokenExpired(String token) {
        return extractAllClaims(token).getExpiration().before(new Date());
    }
}

This utility class handles token creation and validation, ensuring it’s secure with a secret key.

Step 4: Create Authentication Controller

Set up a simple authentication endpoint to generate the JWT token:

import org.springframework.web.bind.annotation.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.http.ResponseEntity;

@RestController
@RequestMapping("/auth")
public class AuthController {

    @Autowired
    private AuthenticationManager authenticationManager;
    @Autowired
    private JwtUtil jwtUtil;
    @Autowired
    private UserDetailsService userDetailsService;

    @PostMapping("/login")
    public ResponseEntity<String> login(@RequestParam String username, @RequestParam String password) throws Exception {
        try {
            authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, password));
        } catch (Exception e) {
            throw new Exception("Invalid username or password");
        }
        final UserDetails userDetails = userDetailsService.loadUserByUsername(username);
        final String jwt = jwtUtil.generateToken(userDetails.getUsername());
        return ResponseEntity.ok(jwt);
    }
}

In this AuthController, we define a login endpoint that authenticates the user and returns a JWT token.

Testing the JWT Authentication

Run your Spring Boot application and use tools like Postman to test the login functionality:

  • To log in, send a POST request to http://localhost:8080/auth/login with username and password parameters.
  • Upon successful authentication, you will receive a JWT token as a response. You can use this token to access secured endpoints.

Best Practices for JWT Authentication

  • Short Expiration Times: Keep JWTs short-lived to reduce the likelihood of misuse.
  • Secure Storage: Store JWTs securely in the client, ideally in an HttpOnly cookie.
  • Revocation Strategies: Consider implementing token revocation strategies in case of compromise.
  • Validation: Always validate the JWT’s signature and claims at server-side on each request.

Conclusion

Implementing JWT in your Spring Boot applications streamlines authentication and enhances security. By following the steps in this post, you can set up a reliable authentication mechanism that protects your services while providing flexibility to clients.

Want to learn more about Java Core? Join the Java Core in Practice course now!

To learn more about ITER Academy, visit our website.

Scroll to Top