Spring Boot – Security & Reliability
1️⃣ JWT Authentication Flow
JWT (JSON Web Token) is a stateless authentication mechanism.
🔄 Flow
Client sends login request (
username + password)Spring Security authenticates user
Server generates a JWT
Client stores JWT (usually in memory or HttpOnly cookie)
Client sends JWT in every request header:
Authorization: Bearer <token>Server validates the token before processing request
🧱 Implementation Structure
SecurityConfigJwtUtilJwtFilterUserDetailsServiceAuthentication Controller
🔹 Example: Security Configuration (Spring Boot 3)
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.csrf(csrf -> csrf.disable())
.sessionManagement(session -> session
.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeHttpRequests(auth -> auth
.requestMatchers("/auth/**").permitAll()
.anyRequest().authenticated()
);
return http.build();
}
🔹 JWT Structure
JWT contains:
Header
Payload (username, roles, expiry)
Signature
⚠️ Best Practices
Keep token expiry short (15–60 min)
Use refresh tokens
Store secret securely (not hardcoded)
Always validate expiration
2️⃣ Role-Based Authorization
Authentication = Who are you?
Authorization = What can you do?
🔹 Define Roles
public enum Role {
ROLE_USER,
ROLE_ADMIN
}
🔹 Secure Endpoints
@PreAuthorize("hasRole('ADMIN')")
@GetMapping("/admin/data")
public String adminOnly() {
return "Admin data";
}
🔹 Enable Method Security
@EnableMethodSecurity
🔐 Example Access Rules
.authorizeHttpRequests(auth -> auth
.requestMatchers("/admin/**").hasRole("ADMIN")
.requestMatchers("/user/**").hasAnyRole("USER", "ADMIN")
.anyRequest().authenticated()
)
⚠️ Common Mistakes
❌ Forgetting ROLE_ prefix
❌ Not enabling method security
❌ Storing roles as plain strings without validation
3️⃣ Securing Endpoints Properly
🔹 Public vs Protected
| Endpoint Type | Example |
|---|---|
| Public | /auth/login |
| Protected | /orders |
| Admin Only | /admin/users |
🔹 Additional Protections
Enable HTTPS (production mandatory)
Disable CSRF only for stateless APIs
Use CORS configuration carefully
Validate input (
@Valid)
🔹 Global Exception Handling
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
public ResponseEntity<String> handleException(Exception ex) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body("Something went wrong");
}
}
Prevents leaking internal stack traces.
4️⃣ Idempotent APIs (Prevent Data Corruption)
Idempotent = Multiple identical requests → same result.
🔹 Safe Methods (HTTP Standard)
| Method | Idempotent? |
|---|---|
| GET | ✅ Yes |
| PUT | ✅ Yes |
| DELETE | ✅ Yes |
| POST | ❌ No (usually) |
🔹 Example Problem
User clicks “Pay” button 3 times → 3 payments processed ❌
🔹 Solution 1: Idempotency Key
Client sends unique key:
Idempotency-Key: 12345-abc
Server:
Store key in DB
If same key comes again → return previous response
🔹 Solution 2: Database Constraints
Use:
Unique constraints
Optimistic locking (
@Version)Transactions
🔹 Optimistic Lock Example
@Version
private Long version;
Prevents lost updates.
🔹 Transaction Best Practice
@Transactional
public void transferMoney(...) {
...
}
Ensures atomicity.
🔥 Security & Reliability Checklist
✅ Stateless authentication (JWT)
✅ Role-based access control
✅ Proper endpoint restrictions
✅ Input validation
✅ Global exception handling
✅ Idempotent critical operations
✅ Use transactions
✅ DB constraints
🚨 Real-World Failures You Avoid
Unauthorized data access
Privilege escalation
Duplicate payments
Lost updates
Data corruption
Session hijacking
ADVANCED SECURITY (Beyond Basic JWT)
1️⃣ Refresh Token Strategy (Very Important)
Access Token → short life (15–30 mins)
Refresh Token → long life (7–30 days)
Why?
Limits damage if token is stolen
Better UX
Two approaches:
Store refresh token in DB
Store in Redis
Rotate refresh tokens (more secure)
2️⃣ Password Security
Never store ra
w passwords.
Use:
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
BCrypt:
Automatically salts
Slow hashing (prevents brute force)
3️⃣ Rate Limiting (Prevent Brute Force / DDoS)
Protect:
/login/register/payment
Tools:
Bucket4j
Redis rate limiting
API Gateway throttling
4️⃣ CORS Proper Configuration
Bad CORS = anyone can call your API.
Example:
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("https://yourfrontend.com")
.allowedMethods("GET", "POST", "PUT", "DELETE");
}
};
}
5️⃣ CSRF (When Needed)
Disable only for stateless APIs
Enable for session-based apps
6️⃣ Security Headers
Add:
HSTS
X-Content-Type-Options
X-Frame-Options
Content-Security-Policy
Spring Security handles many automatically.
🛡 RELIABILITY – More Than Idempotency
7️⃣ Circuit Breaker (Microservices)
If another service fails → prevent cascading failure.
Use:
Resilience4j
Prevents:
System-wide crash
8️⃣ Retry Mechanism
For temporary DB/network failures:
@Retryable(maxAttempts = 3)
9️⃣ Timeout Configuration
Never allow infinite waits.
Configure:
DB connection pool timeout
HTTP client timeout
🔟 Logging & Monitoring
You need:
Structured logging
Log levels
Correlation IDs
Metrics (Micrometer)
Health checks (
/actuator/health)
1️⃣1️⃣ Audit Logging
Track:
Who changed data
When
What changed
Very important for financial systems.
1️⃣2️⃣ Database-Level Safety
Unique constraints
Foreign keys
Indexing
Proper isolation level
Avoid long transactions
🎯 Senior-Level Additions
OAuth2
OpenID Connect
API Gateway security
Token blacklisting (logout support)
Multi-factor authentication
Encryption of sensitive fields
Secure secrets management (Vault)