Implementing JWT Authentication in Spring Boot Security (Full Example)

4 min read

Implementing JWT Authentication in Spring Boot Security (Full Example)

Overview

JSON Web Token (JWT) is a compact and self-contained way of securely transmitting information between parties. In modern applications, it is commonly used for securing APIs by validating tokens sent by the client.

In this article, you’ll learn how to:

  • Build a REST API secured with Spring Security and JWT
  • Authenticate users and generate JWTs
  • Validate incoming JWTs for protected routes

Tools & Dependencies

  • Java 17+
  • Spring Boot 3.x
  • Maven
  • Spring Web, Spring Security, Spring Boot Starter Data JPA
  • H2 Database (for demo)
  • jjwt for JWT operations

Project Structure

src/main/java/com/example/jwtsecurity/
├── controller/
│   └── AuthController.java
├── dto/
│   └── AuthRequest.java
│   └── AuthResponse.java
├── model/
│   └── User.java
├── repository/
│   └── UserRepository.java
├── security/
│   └── JwtFilter.java
│   └── JwtUtil.java
│   └── SecurityConfig.java
├── service/
│   └── UserService.java
├── JwtSecurityApplication.java

Step-by-Step Implementation

1. Add Dependencies (pom.xml)

<dependencies>
    <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>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
        <scope>runtime</scope>
    </dependency>
</dependencies>

2. User Entity

@Entity
public class User {
    @Id
    @GeneratedValue
    private Long id;
    private String username;
    private String password;
    private String role;
}

3. DTOs

AuthRequest.java

public class AuthRequest {
    private String username;
    private String password;
}

AuthResponse.java

public class AuthResponse {
    private String token;

    public AuthResponse(String token) {
        this.token = token;
    }

    public String getToken() {
        return token;
    }
}

4. JWT Utility

JwtUtil.java

@Component
public class JwtUtil {

    private final String SECRET_KEY = "mysecret";

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

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

    public boolean validateToken(String token, UserDetails userDetails) {
        String username = extractUsername(token);
        return (username.equals(userDetails.getUsername()));
    }
}

5. Security Configuration

SecurityConfig.java

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Autowired
    private JwtFilter jwtFilter;

    @Autowired
    private UserService userService;

    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration config) throws Exception {
        return config.getAuthenticationManager();
    }

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.csrf().disable()
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/auth").permitAll()
                .anyRequest().authenticated()
            )
            .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS));

        http.addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class);
        return http.build();
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

6. JWT Filter

JwtFilter.java

@Component
public class JwtFilter extends OncePerRequestFilter {

    @Autowired
    private JwtUtil jwtUtil;

    @Autowired
    private UserService userService;

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

        final String authHeader = request.getHeader("Authorization");
        String username = null;
        String jwt = null;

        if (authHeader != null && authHeader.startsWith("Bearer ")) {
            jwt = authHeader.substring(7);
            username = jwtUtil.extractUsername(jwt);
        }

        if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
            UserDetails userDetails = userService.loadUserByUsername(username);
            if (jwtUtil.validateToken(jwt, userDetails)) {
                UsernamePasswordAuthenticationToken token =
                    new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
                token.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                SecurityContextHolder.getContext().setAuthentication(token);
            }
        }

        filterChain.doFilter(request, response);
    }
}

7. User Service

UserService.java

@Service
public class UserService implements UserDetailsService {

    @Autowired
    private UserRepository userRepo;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = userRepo.findByUsername(username)
            .orElseThrow(() -> new UsernameNotFoundException("User not found"));

        return new org.springframework.security.core.userdetails.User(
            user.getUsername(),
            user.getPassword(),
            List.of(new SimpleGrantedAuthority(user.getRole()))
        );
    }
}

8. Authentication Endpoint

AuthController.java

@RestController
public class AuthController {

    @Autowired
    private AuthenticationManager authManager;

    @Autowired
    private JwtUtil jwtUtil;

    @Autowired
    private UserService userService;

    @PostMapping("/auth")
    public ResponseEntity<AuthResponse> authenticate(@RequestBody AuthRequest request) {
        try {
            authManager.authenticate(
                new UsernamePasswordAuthenticationToken(request.getUsername(), request.getPassword()));
        } catch (AuthenticationException e) {
            throw new RuntimeException("Invalid Credentials");
        }

        String token = jwtUtil.generateToken(request.getUsername());
        return ResponseEntity.ok(new AuthResponse(token));
    }

    @GetMapping("/hello")
    public String hello() {
        return "Hello, Authenticated User!";
    }
}

9. Data Initialization (Optional)

CommandLineRunner for demo

@Bean
CommandLineRunner init(UserRepository repo, PasswordEncoder encoder) {
    return args -> {
        User user = new User();
        user.setUsername("user");
        user.setPassword(encoder.encode("password"));
        user.setRole("ROLE_USER");
        repo.save(user);
    };
}

Example Flow

  1. Send POST /auth with JSON: { "username": "user", "password": "password" }
  2. Receive JWT token in response.
  3. Access protected route /hello using: Authorization: Bearer <token>

Conclusion

Using JWT with Spring Boot Security is a clean, stateless way to protect your REST APIs. By decoupling session management, this architecture scales better for modern microservices and SPAs.

🤞 Never miss a story from us, get weekly updates to your inbox!

Leave a Reply

Your email address will not be published. Required fields are marked *