A comprehensive Spring Security implementation covering authentication, authorization, JWT tokens, OAuth2, role-based access control, and advanced security features. This project demonstrates production-ready security mechanisms with real-world examples and best practices.
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Client App │────│ Security Chain │────│ Authentication │
└─────────────────┘ └─────────────────┘ └─────────────────┘
│
┌───────────┼───────────┐
│ │ │
┌───────▼────┐ ┌────▼────┐ ┌───▼──────┐
│ JWT │ │ OAuth2 │ │ RBAC │
│ Filter │ │ Client │ │ Filter │
└────────────┘ └─────────┘ └──────────┘
│ │ │
└───────────┼───────────┘
│
┌───────────▼───────────┐
│ Security Context │
│ & User Details │
└─────────────────────--┘
- JWT Authentication with Access & Refresh Tokens
- OAuth2 Integration with Google Sign-In
- Role-Based Access Control (RBAC)
- Method-Level Security with annotations
- Session Management with database persistence
- Password Encryption using BCrypt
- Custom Security Filters and Filter Chain
- CSRF Protection and mitigation strategies
- XSS Prevention techniques
- SQL Injection protection
- Custom Exception Handling for auth failures
- Token Validation and expiration handling
- Stateless Authentication architecture
- Granular Permissions system
- Dynamic Role Assignment
- Token Refresh Mechanism
- Custom Authentication Providers
- Security Method Annotations
- Cookie-based Token Storage
| Category | Technology | Purpose |
|---|---|---|
| Framework | Spring Boot 3.x | Application foundation |
| Security | Spring Security 6.x | Authentication & Authorization |
| Authentication | JWT | Stateless token-based auth |
| OAuth2 | Google OAuth2 | Third-party authentication |
| Database | JPA/Hibernate | User & session persistence |
| Password | BCrypt | Secure password hashing |
| Build Tool | Maven | Dependency management |
| Java | Java 21 | Programming language |
- ☕ Java 21+
- 📦 Maven 3.8+
- 🗄️ Database (H2/MySQL/PostgreSQL)
- 🌐 Google OAuth2 Credentials (for OAuth features)
-
Clone the repository
git clone https://github.com/ARONAGENT/Spring_Security_All.git cd Spring_Security_All -
Configure Google OAuth2 (Optional)
# application.yml spring: security: oauth2: client: registration: google: client-id: your-google-client-id client-secret: your-google-client-secret
-
Run the application
./mvnw spring-boot:run
-
Access the application
- 🌐 Main App: http://localhost:8080
- 📖 Swagger UI: http://localhost:8080/swagger-ui.html
- 🔐 Login: http://localhost:8080/login
@Configuration
@EnableWebSecurity
@EnableMethodSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
return http
.csrf(csrf -> csrf.disable())
.authorizeHttpRequests(auth -> auth
.requestMatchers("/auth/**").permitAll()
.requestMatchers("/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
)
.sessionManagement(session ->
session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
)
.addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class)
.build();
}
}@Service
public class CustomUserDetailsService implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String username) {
// Load user from database
// Convert to UserDetails with roles and authorities
}
}@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder(12);
}- Header: Algorithm and token type
- Payload: User claims and metadata
- Signature: Verification signature
@Service
public class JwtService {
public String generateToken(UserDetails userDetails) {
return Jwts.builder()
.setSubject(userDetails.getUsername())
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 10))
.signWith(getSignInKey(), SignatureAlgorithm.HS256)
.compact();
}
public String generateRefreshToken(UserDetails userDetails) {
return Jwts.builder()
.setSubject(userDetails.getUsername())
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 24 * 7))
.signWith(getSignInKey(), SignatureAlgorithm.HS256)
.compact();
}
}- User Login → Validate credentials
- Generate Tokens → Access + Refresh tokens
- Store in Cookies → Secure HTTP-only cookies
- Validate Requests → JWT filter validation
- Token Refresh → Generate new access token
spring:
security:
oauth2:
client:
registration:
google:
client-id: ${GOOGLE_CLIENT_ID}
client-secret: ${GOOGLE_CLIENT_SECRET}
scope: openid,profile,email
provider:
google:
authorization-uri: https://accounts.google.com/o/oauth2/auth
token-uri: https://oauth2.googleapis.com/token
user-info-uri: https://www.googleapis.com/oauth2/v2/userinfo@Component
public class OAuth2SuccessHandler implements AuthenticationSuccessHandler {
@Override
public void onAuthenticationSuccess(HttpServletRequest request,
HttpServletResponse response,
Authentication authentication) {
OAuth2User oAuth2User = (OAuth2User) authentication.getPrincipal();
String email = oAuth2User.getAttribute("email");
// Create or update user
// Generate JWT token
// Redirect to dashboard
}
}@Entity
public class User {
private String username;
private String password;
private String email;
@ManyToMany(fetch = FetchType.EAGER)
private Set<Role> roles;
}
@Entity
public class Role {
private String name; // ADMIN, USER, CREATOR
@ManyToMany(fetch = FetchType.EAGER)
private Set<Permission> permissions;
}
@Entity
public class Permission {
private String name; // READ, WRITE, DELETE
}@RestController
public class AdminController {
@PreAuthorize("hasRole('ADMIN')")
@GetMapping("/admin/users")
public List<User> getAllUsers() {
return userService.findAll();
}
@PreAuthorize("hasAuthority('DELETE_USER')")
@DeleteMapping("/admin/users/{id}")
public void deleteUser(@PathVariable Long id) {
userService.deleteById(id);
}
@Secured({"ROLE_ADMIN", "ROLE_CREATOR"})
@PostMapping("/admin/posts")
public Post createPost(@RequestBody Post post) {
return postService.save(post);
}
}@Entity
public class UserSession {
private String sessionId;
private String username;
private String jwtToken;
private LocalDateTime createdAt;
private LocalDateTime expiresAt;
private boolean active;
}@Service
public class SessionService {
public void createSession(String username, String jwtToken) {
UserSession session = new UserSession();
session.setUsername(username);
session.setJwtToken(jwtToken);
session.setActive(true);
sessionRepository.save(session);
}
public boolean isSessionValid(String token) {
return sessionRepository.findByJwtTokenAndActiveTrue(token)
.map(session -> session.getExpiresAt().isAfter(LocalDateTime.now()))
.orElse(false);
}
}@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
String authHeader = request.getHeader("Authorization");
String jwt = null;
String username = null;
if (authHeader != null && authHeader.startsWith("Bearer ")) {
jwt = authHeader.substring(7);
username = jwtService.extractUsername(jwt);
}
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
if (jwtService.isTokenValid(jwt, userDetails)) {
UsernamePasswordAuthenticationToken authToken =
new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(authToken);
}
}
filterChain.doFilter(request, response);
}
}@Component
public class LoggingFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
log.info("Request: {} {}", httpRequest.getMethod(), httpRequest.getRequestURI());
chain.doFilter(request, response);
log.info("Response processed for: {}", httpRequest.getRequestURI());
}
}@Component
public class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response,
AuthenticationException authException) throws IOException {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.setContentType("application/json");
String jsonResponse = """
{
"error": "Unauthorized",
"message": "Authentication required",
"timestamp": "%s",
"path": "%s"
}
""".formatted(Instant.now(), request.getRequestURI());
response.getWriter().write(jsonResponse);
}
}@ControllerAdvice
public class JwtExceptionHandler {
@ExceptionHandler(JwtException.class)
public ResponseEntity<ErrorResponse> handleJwtException(JwtException ex) {
ErrorResponse error = new ErrorResponse("JWT_ERROR", ex.getMessage());
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(error);
}
@ExceptionHandler(ExpiredJwtException.class)
public ResponseEntity<ErrorResponse> handleExpiredJwtException(ExpiredJwtException ex) {
ErrorResponse error = new ErrorResponse("TOKEN_EXPIRED", "JWT token has expired");
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(error);
}
}How.to.Get.New.Access.Token.with.Refresh.token.in.Postman.Spring.Boot.mp4
default.JWT.session.management.with.one.active.session.mp4
OAuth2Client.Authentication.mp4
ROLE.BASED.Authority.In.Spring.security.mp4
1.Internal Working - Spring Security Working Flow.pdf
2.JWT And Refresh Token - JWT and Refresh Token.pdf
3.Steps of Oauth2Client Registration - OAuth2Client - GOOGLE.pdf
4.Session Management - Session Management in Spring Security.pdf
5.Role Based Authority - Role Based Authorization And Granular based Authorization and Security Annotations.pdf
POST /auth/signup # User registration
POST /auth/login # User login
POST /auth/refresh # Refresh access token
POST /auth/logout # User logoutGET /post/** # All users (ADMIN only)
PUT /post/** # Update user (ADMIN only)GET /login/authorization/google # Google OAuth2 login
GET /login/oauth2/code/google # Google OAuth2 callbackjwt:
secret: your-secret-key
expiration: 86400000 # 24 hours
refresh-expiration: 604800000 # 7 daysspring:
security:
require-ssl: true
headers:
frame-options: DENY
content-type-options: nosniff@PostMapping("/admin/users/{id}/roles")
@PreAuthorize("hasRole('ADMIN')")
public ResponseEntity<?> assignRole(@PathVariable Long id, @RequestBody RoleRequest request) {
userService.assignRole(id, request.getRoleName());
return ResponseEntity.ok().build();
}@PreAuthorize("hasPermission(#postId, 'POST', 'DELETE')")
@DeleteMapping("/posts/{postId}")
public ResponseEntity<?> deletePost(@PathVariable Long postId) {
postService.delete(postId);
return ResponseEntity.ok().build();
}@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@PreAuthorize("hasRole('ADMIN') or (hasRole('CREATOR') and #userId == authentication.principal.id)")
public @interface AdminOrOwner {
}
@AdminOrOwner
@PutMapping("/users/{userId}")
public ResponseEntity<User> updateUser(@PathVariable Long userId, @RequestBody User user) {
return ResponseEntity.ok(userService.update(userId, user));
}This project demonstrates:
- ✅ Complete Spring Security implementation
- ✅ JWT Authentication with refresh tokens
- ✅ OAuth2 Integration with Google
- ✅ Role-Based Authorization (RBAC)
- ✅ Method-Level Security with annotations
- ✅ Exception Handling for security failures
- ✅ Session Management with database persistence
- ✅ Production-Ready security features
- Multi-factor Authentication (MFA)
- Redis-based session storage
- Rate limiting implementation
- Security audit logging
- Password policy enforcement
- Account lockout mechanism
- Social login with multiple providers
- API key authentication
- SAML integration
Rohan Uke
Backend Developer | Java & Spring Security Expert
Give a ⭐️ if this project helped you understand Spring Security!
If you have any questions or need help with the project, please:
- Check the Issues page
- Create a new issue if your question isn't already answered
- Contact me via LinkedIn
Built with ❤️ using Spring Security and modern security practices



















