Authentication Strategies Comparison
Authentication Strategy | Description | Use Case |
Session-Based Authentication | Stores user session in the server (stateful) | Monolithic apps, Spring Security with sessions |
JWT-Based Authentication (Without Refresh Token) |
Uses a single JWT for authentication, but requires re-login when expired | Simple stateless APIs |
JWT + Refresh Token (This Strategy) |
Uses a short-lived access token + a long-lived refresh token for session renewal | Microservices, scalable REST APIs |
OAuth 2.0 Authorization Code Flow | Uses authorization servers (e.g., Google, Facebook) with refresh tokens | Third-party authentication |
* OAuth (Open Authorization) is an industry-standard protocol
How Refresh Tokens Work (Flow)
Step 1: User Logs In : The client sends username/password to the authentication server.
- The server validates credentials and returns:
- Access Token (Short-lived, e.g., 15 min) Refresh Token (Long-lived, e.g., 7 days)
Step 2: Using the Access Token :
- The client includes the access token in API requests and The server validates
Step 3: Access Token Expires :
- When the access token expires, the client gets a 401 Unauthorized response.
- Case 1: Client Does Nothing Until the Access Token Expires ( User Experience Impact)
- Case 2: Client Proactively Refreshes Before Expiry ( No User Experience Impact)
- The client keep track of when the access token expires and refresh it before it actually expires.
Step 4: Client Requests a New Access Token Using the Refresh Token
- The client sends the refresh token to the authentication server.
- If the refresh token is valid, the server issues a new access token.
Step 5: Client Uses the New Access Token
- The client resumes API requests using the new access token.
Implementing Refresh Token
- refresh tokens need to be stored in a database (or another persistent storage like Redis) instead of keeping them in memory.
- To Immediately revokr yorkn
- to minimize unnecessary storage growth when using black list
- To prevent replay attacks✅ Better database performance ✔ Blacklisting is useful for long-
import lombok.RequiredArgsConstructor;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Service;
import java.time.Instant;
import java.util.Optional;
import java.util.UUID;
@Service
@RequiredArgsConstructor
public class AuthService {
private final AuthenticationManager authenticationManager;
private final UserDetailsService userDetailsService;
private final JwtUtil jwtUtil;
private final RefreshTokenRepository refreshTokenRepository;
private final UserRepository userRepository;
public AuthResponse authenticate(LoginRequest request) {
authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(request.getEmail(), request.getPassword())
);
UserDetails userDetails = userDetailsService.loadUserByUsername(request.getEmail());
String accessToken = jwtUtil.generateAccessToken(userDetails.getUsername());
String refreshToken = createRefreshToken(userDetails.getUsername());
return new AuthResponse(accessToken, refreshToken);
}
private String createRefreshToken(String username) {
UserEntity user = userRepository.findByEmail(username)
.orElseThrow(() -> new RuntimeException("User not found"));
RefreshToken refreshToken = new RefreshToken();
refreshToken.setToken(UUID.randomUUID().toString());
refreshToken.setUser(user);
refreshToken.setExpiryDate(Instant.now().plusSeconds(7 * 24 * 60 * 60)); // 7 days
refreshTokenRepository.save(refreshToken);
return refreshToken.getToken();
}
public AuthResponse refreshToken(RefreshTokenRequest request) {
Optional<RefreshToken> storedToken = refreshTokenRepository.findByToken(request.getRefreshToken());
if (storedToken.isEmpty() || storedToken.get().getExpiryDate().isBefore(Instant.now())) {
throw new RuntimeException("Invalid or expired refresh token");
}
String username = storedToken.get().getUser().getEmail();
String newAccessToken = jwtUtil.generateAccessToken(username);
return new AuthResponse(newAccessToken, request.getRefreshToken());
}
public void logout(String username) {
UserEntity user = userRepository.findByEmail(username)
.orElseThrow(() -> new RuntimeException("User not found"));
refreshTokenRepository.deleteByUser(user);
}
}
'개발기술 > 보안' 카테고리의 다른 글
브라우저 보안정책 (0) | 2025.02.26 |
---|---|
네트워크 접근제어(NAC) ; NAT, 방화벽 (0) | 2025.02.25 |
보안의 개념과 기술 (0) | 2025.01.19 |
HTTPS 의 TLS 동작과정 (0) | 2025.01.18 |
Security JWT,세션, 쿠키방식 (0) | 2025.01.15 |