Building a JWT Authentication System with Spring Boot


Authentication is a critical component of modern web applications. In this blog, weโll walk through creating a JWT (JSON Web Token) Authentication System using Spring Boot. This project demonstrates how to secure RESTful APIs with Spring Security and JWT.
By the end of this blog, youโll have a fully functional authentication system, complete with:
User registration.
Role-based access control (e.g., ADMIN, USER).
Token-based authentication using JWT.
๐ 1. Introduction: What are we building and why?
This project is a JWT Authentication System that utilizes:
Spring Security for securing endpoints.
JWT (JSON Web Tokens) for stateless authentication.
MySQL Database to store user credentials.
Key features:
User Registration: Add new users with encrypted passwords.
Authentication: Validate user credentials to issue JWT tokens.
Role-Based Access: Restrict access based on roles like ADMIN and USER.
Token Validation: Validate tokens for secure access to protected endpoints.
This project is perfect for:
Learning Spring Security and JWT integration.
Implementing role-based access control in RESTful APIs.
Building secure, stateless authentication systems.
๐ 2. Backend Architecture
MyUser Entity
The MyUser
class represents the user entity stored in the database. It includes fields for:
Username and Password.
Role for access control.
@Entity
public class MyUser {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String username;
private String password;
private String role; // Eg: ADMIN, USER
// Getters and Setters...
}
MyUserRepository
The MyUserRepository
extends JpaRepository
and provides a method to find users by their username.
@Repository
public interface MyUserRepository extends JpaRepository<MyUser, Long> {
Optional<MyUser> findByUsername(String username);
}
MyUserDetailService
The MyUserDetailService
implements UserDetailsService
to load user details from the database for Spring Security.
@Service
public class MyUserDetailService implements UserDetailsService {
@Autowired
private MyUserRepository repository;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
Optional<MyUser> user = repository.findByUsername(username);
if (user.isPresent()) {
var userObj = user.get();
return User.builder()
.username(userObj.getUsername())
.password(userObj.getPassword())
.roles(userObj.getRole().split(","))
.build();
} else {
throw new UsernameNotFoundException(username);
}
}
}
JwtService
The JwtService
handles JWT generation, validation, and extraction of user information.
@Service
public class JwtService {
private static final String SECRET = "YOUR_SECRET_KEY_HERE";
private static final long VALIDITY = TimeUnit.MINUTES.toMillis(30);
public String generateToken(UserDetails userDetails) {
Map<String, String> claims = new HashMap<>();
claims.put("iss", "https://secure.genuinecoder.com");
return Jwts.builder()
.claims(claims)
.subject(userDetails.getUsername())
.issuedAt(Date.from(Instant.now()))
.expiration(Date.from(Instant.now().plusMillis(VALIDITY)))
.signWith(Keys.hmacShaKeyFor(Base64.getDecoder().decode(SECRET)))
.compact();
}
public String extractUsername(String jwt) {
Claims claims = Jwts.parserBuilder()
.setSigningKey(Keys.hmacShaKeyFor(Base64.getDecoder().decode(SECRET)))
.build()
.parseClaimsJws(jwt)
.getBody();
return claims.getSubject();
}
public boolean isTokenValid(String jwt) {
Claims claims = Jwts.parserBuilder()
.setSigningKey(Keys.hmacShaKeyFor(Base64.getDecoder().decode(SECRET)))
.build()
.parseClaimsJws(jwt)
.getBody();
return claims.getExpiration().after(Date.from(Instant.now()));
}
}
ContentController
The ContentController
exposes endpoints for:
Home: Public access.
Admin Home: Restricted to ADMIN.
User Home: Restricted to USER.
Authentication: Validate credentials and return a JWT token.
@RestController
public class ContentController {
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private JwtService jwtService;
@Autowired
private MyUserDetailService myUserDetailService;
@GetMapping("/home")
public String handleWelcome() {
return "Welcome to home!";
}
@GetMapping("/admin/home")
public String handleAdminHome() {
return "Welcome to ADMIN home!";
}
@GetMapping("/user/home")
public String handleUserHome() {
return "Welcome to USER home!";
}
@PostMapping("/authenticate")
public String authenticateAndGetToken(@RequestBody LoginForm loginForm) {
Authentication authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(
loginForm.username(), loginForm.password()
));
if (authentication.isAuthenticated()) {
return jwtService.generateToken(myUserDetailService.loadUserByUsername(loginForm.username()));
} else {
throw new UsernameNotFoundException("Invalid credentials");
}
}
}
SecurityConfiguration
The SecurityConfiguration
class configures Spring Security:
Defines public and protected routes.
Associates roles (ADMIN and USER) with specific endpoints.
Adds the
JwtAuthenticationFilter
for token validation.
@Configuration
@EnableWebSecurity
public class SecurityConfiguration {
@Autowired
private MyUserDetailService userDetailService;
@Autowired
private JwtAuthenticationFilter jwtAuthenticationFilter;
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {
return httpSecurity
.csrf(AbstractHttpConfigurer::disable)
.authorizeHttpRequests(registry -> {
registry.requestMatchers("/home", "/register/**", "/authenticate").permitAll();
registry.requestMatchers("/admin/**").hasRole("ADMIN");
registry.requestMatchers("/user/**").hasRole("USER");
registry.anyRequest().authenticated();
})
.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)
.build();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
๐โโ๏ธ 3. How to Run It
Prerequisites:
Java 21 or later.
MySQL Database running locally.
Steps:
Clone the GitHub repository:
git clone https://github.com/Mayurdpatil67/springboot-security-authenticator.git cd springboot-security-authenticator
Configure the database in
application.properties
:spring.datasource.url=jdbc:mysql://localhost:3306/jwtdb spring.datasource.username=root spring.datasource.password=yourpassword
Run the Spring Boot application:
./gradlew bootRun
Test the API endpoints using tools like Postman or curl.
๐ 4. GitHub Repository
The complete source code for this project is available on GitHub. Feel free to clone, fork, or contribute to the repository:
GitHub Link: JWT Authentication System
๐ 5. Conclusion
This project demonstrates how to implement a secure JWT authentication system with Spring Boot. Youโve learned:
How to configure Spring Security for role-based access control.
How to use JWT for stateless authentication.
How to secure RESTful APIs with Spring Boot.
Whatโs Next?
Add refresh tokens for better token management.
Implement logout functionality by revoking tokens.
Extend the system to include OAuth2 for third-party authentication.
Happy coding! ๐๐
Subscribe to my newsletter
Read articles from Mayur Patil directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Mayur Patil
Mayur Patil
Skilled in Java & Spring Boot , Backedn Enthusiast