Here's a step-by-step guide to implementing JWT Authentication in a Spring Boot application, in a clean, structured, and modular way:
โ Technologies Used:
- Spring Boot 3.x
- Spring Security
- JWT (JSON Web Token)
- Maven or Gradle
- Java 17+
- JPA & H2/MySQL (optional)
๐งฑ Project Structure
src/main/java/com/example/jwtsecurity
โ
โโโ config
โ โโโ SecurityConfig.java
โ
โโโ controller
โ โโโ AuthController.java
โ
โโโ dto
โ โโโ AuthRequest.java
โ โโโ AuthResponse.java
โ
โโโ entity
โ โโโ User.java
โ
โโโ repository
โ โโโ UserRepository.java
โ
โโโ security
โ โโโ JwtAuthenticationFilter.java
โ โโโ JwtTokenProvider.java
โ โโโ CustomUserDetailsService.java
โ
โโโ service
โ โโโ AuthService.java
โ
โโโ JwtSecurityApplication.java
1๏ธโฃ Add Maven Dependencies (pom.xml
)
<dependencies>
<!-- Spring Boot Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring Security -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- JWT -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
<!-- JPA and H2 (or switch to MySQL) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>
</dependencies>
2๏ธโฃ Create User Entity
// entity/User.java
package com.example.jwtsecurity.entity;
import jakarta.persistence.*;
import lombok.*;
@Entity
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class User {
@Id
@GeneratedValue
private Long id;
private String username;
private String password;
private String role;
}
3๏ธโฃ Create UserRepository
// repository/UserRepository.java
package com.example.jwtsecurity.repository;
import com.example.jwtsecurity.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.Optional;
public interface UserRepository extends JpaRepository<User, Long> {
Optional<User> findByUsername(String username);
}
4๏ธโฃ DTOs
// dto/AuthRequest.java
package com.example.jwtsecurity.dto;
import lombok.*;
@Data
public class AuthRequest {
private String username;
private String password;
}
// dto/AuthResponse.java
package com.example.jwtsecurity.dto;
import lombok.*;
@Data
@AllArgsConstructor
public class AuthResponse {
private String token;
}
5๏ธโฃ JwtTokenProvider
// security/JwtTokenProvider.java
package com.example.jwtsecurity.security;
import io.jsonwebtoken.*;
import org.springframework.stereotype.Component;
import java.util.Date;
@Component
public class JwtTokenProvider {
private final String JWT_SECRET = "secret_key";
private final long JWT_EXPIRATION = 604800000L;
public String generateToken(String username) {
return Jwts.builder()
.setSubject(username)
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + JWT_EXPIRATION))
.signWith(SignatureAlgorithm.HS512, JWT_SECRET)
.compact();
}
public String getUsernameFromToken(String token) {
return Jwts.parser()
.setSigningKey(JWT_SECRET)
.parseClaimsJws(token)
.getBody()
.getSubject();
}
public boolean validateToken(String token) {
try {
Jwts.parser().setSigningKey(JWT_SECRET).parseClaimsJws(token);
return true;
} catch (JwtException ex) {
return false;
}
}
}
6๏ธโฃ CustomUserDetailsService
// security/CustomUserDetailsService.java
package com.example.jwtsecurity.security;
import com.example.jwtsecurity.entity.User;
import com.example.jwtsecurity.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.*;
import org.springframework.stereotype.Service;
@Service
public class CustomUserDetailsService implements UserDetailsService {
@Autowired
private UserRepository userRepository;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findByUsername(username)
.orElseThrow(() -> new UsernameNotFoundException("User not found"));
return org.springframework.security.core.userdetails.User
.withUsername(user.getUsername())
.password(user.getPassword())
.roles(user.getRole())
.build();
}
}
7๏ธโฃ JwtAuthenticationFilter
// security/JwtAuthenticationFilter.java
package com.example.jwtsecurity.security;
import jakarta.servlet.*;
import jakarta.servlet.http.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.*;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
import java.io.IOException;
@Component
public class JwtAuthenticationFilter extends GenericFilter {
@Autowired
private JwtTokenProvider jwtTokenProvider;
@Autowired
private CustomUserDetailsService userDetailsService;
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
String header = httpRequest.getHeader("Authorization");
if (header != null && header.startsWith("Bearer ")) {
String token = header.substring(7);
if (jwtTokenProvider.validateToken(token)) {
String username = jwtTokenProvider.getUsernameFromToken(token);
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
UsernamePasswordAuthenticationToken authToken =
new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(authToken);
}
}
chain.doFilter(request, response);
}
}
8๏ธโฃ SecurityConfig
// config/SecurityConfig.java
package com.example.jwtsecurity.config;
import com.example.jwtsecurity.security.JwtAuthenticationFilter;
import com.example.jwtsecurity.security.CustomUserDetailsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.*;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.*;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.crypto.bcrypt.*;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
public class SecurityConfig {
@Autowired
private JwtAuthenticationFilter jwtAuthenticationFilter;
@Autowired
private CustomUserDetailsService userDetailsService;
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.csrf(csrf -> csrf.disable())
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/auth/**").permitAll()
.anyRequest().authenticated()
)
.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
return http.build();
}
@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration configuration)
throws Exception {
return configuration.getAuthenticationManager();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
9๏ธโฃ AuthService
// service/AuthService.java
package com.example.jwtsecurity.service;
import com.example.jwtsecurity.dto.AuthRequest;
import com.example.jwtsecurity.dto.AuthResponse;
import com.example.jwtsecurity.security.JwtTokenProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.*;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Service;
@Service
public class AuthService {
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private JwtTokenProvider jwtTokenProvider;
public AuthResponse login(AuthRequest request) {
Authentication authentication = authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(request.getUsername(), request.getPassword())
);
String token = jwtTokenProvider.generateToken(authentication.getName());
return new AuthResponse(token);
}
}
๐ AuthController
// controller/AuthController.java
package com.example.jwtsecurity.controller;
import com.example.jwtsecurity.dto.AuthRequest;
import com.example.jwtsecurity.dto.AuthResponse;
import com.example.jwtsecurity.service.AuthService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api/auth")
public class AuthController {
@Autowired
private AuthService authService;
@PostMapping("/login")
public AuthResponse login(@RequestBody AuthRequest request) {
return authService.login(request);
}
}
๐ Main Application
// JwtSecurityApplication.java
package com.example.jwtsecurity;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class JwtSecurityApplication {
public static void main(String[] args) {
SpringApplication.run(JwtSecurityApplication.class, args);
}
}
๐งช Test
- Run the app.
- Hit
POST /api/auth/login
with:
{
"username": "admin",
"password": "admin"
}
- Use the returned token in the
Authorization
header:Bearer <TOKEN>
for protected endpoints.
Top comments (0)