fix: fixing the token expiration issue in AuthService

Adding a fix to validate the token on api calls to ensure that expired tokens are not accepted.
This commit is contained in:
2026-01-18 18:48:26 -05:00
parent 7f1aca8c09
commit 664fb2d651
4 changed files with 57 additions and 12 deletions

View File

@@ -6,7 +6,6 @@ import com.api.main.dto.ErrorResponse;
import com.api.main.dto.UserResponse;
import com.api.main.entity.User;
import com.api.main.services.AuthService;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;
import java.util.Collections;
import java.util.Map;
@@ -53,11 +52,22 @@ public class UserController {
@PreAuthorize("hasRole('ADMIN')")
@PostMapping("/create")
public ResponseEntity<?> createUser(@Valid @RequestBody CreateUserRequest request) {
public ResponseEntity<?> createUser(
@Valid @RequestBody CreateUserRequest request, Authentication authentication) {
try {
Authentication authenticationContext = SecurityContextHolder.getContext().getAuthentication();
if (authenticationContext == null && !authenticationContext.isAuthenticated()) {
return ResponseEntity.status(401)
.body(new ErrorResponse(Constants.ERROR, Constants.UNAUTHORIZED_MESSAGE));
}
String username = authentication.getName();
User user =
authService.registerUser(
request.getUsername(), request.getEmail(), request.getPassword(), request.getRole());
request.getUsername(),
request.getEmail(),
request.getPassword(),
request.getRole(),
username);
UserResponse response =
new UserResponse(
user.getId(),
@@ -71,12 +81,12 @@ public class UserController {
}
@PostMapping("/logout")
public ResponseEntity<?> logout(HttpServletRequest request) {
public ResponseEntity<?> logout() {
try {
String authHeader = request.getHeader("Authorization");
if (authHeader != null && authHeader.startsWith("Bearer ")) {
String token = authHeader.substring(7);
authService.logout(token);
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication != null && authentication.isAuthenticated()) {
String username = authentication.getName();
authService.logoutByUsername(username);
}
return ResponseEntity.ok(
Map.of(

View File

@@ -155,4 +155,8 @@ public class Token {
public void setRevoked(boolean revoked) {
this.revoked = revoked;
}
public Object getRevoked() {
return this.revoked;
}
}

View File

@@ -6,6 +6,7 @@ import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
/*
@@ -39,14 +40,22 @@ public interface TokenRepository extends JpaRepository<Token, Long> {
*/
Optional<Token> findByTokenAndRevokedFalse(String token);
/*
* Find the most recent token for a given username.
* @param username The username associated with the token
* @return Optional containing the most recent Token if found, else empty
*
*/
Optional<Token> findTopByUsernameOrderByExpiresAtDesc(String username);
/*
* Revoke all tokens associated with a specific username.
* @param username The username whose tokens are to be revoked
*
*/
@Modifying
@Modifying(clearAutomatically = true, flushAutomatically = true)
@Query(Constants.ADDING_TOKEN_QUERY)
void revokeAllUserTokens(String username);
void revokeAllUserTokens(@Param("username") String username);
/*
* Delete all expired tokens from the database.

View File

@@ -51,6 +51,13 @@ public class AuthService {
this.authenticationManager = authenticationManager;
}
public boolean isTokenRevokedForUser(String username) {
return tokenRepository
.findTopByUsernameOrderByExpiresAtDesc(username)
.map(Token::isRevoked)
.orElse(true);
}
@Transactional
public LoginResponse authenticate(LoginRequest request) {
try {
@@ -78,7 +85,9 @@ public class AuthService {
private String generateToken() {
byte[] randomBytes = new byte[32];
new java.security.SecureRandom().nextBytes(randomBytes);
return UUID.randomUUID().toString() + "-" + Base64.getUrlEncoder().withoutPadding().encodeToString(randomBytes);
return UUID.randomUUID().toString()
+ "-"
+ Base64.getUrlEncoder().withoutPadding().encodeToString(randomBytes);
}
public UserResponse getCurrentUser(String username) {
@@ -87,6 +96,10 @@ public class AuthService {
.findByUsername(username)
.orElseThrow(() -> new RuntimeException("User not found"));
if (isTokenRevokedForUser(username)) {
throw new RuntimeException("Token is revoked");
}
return new UserResponse(
user.getId(),
user.getUsername(),
@@ -95,7 +108,11 @@ public class AuthService {
}
@Transactional
public User registerUser(String username, String email, String password, String role) {
public User registerUser(
String username, String email, String password, String role, String createdBy) {
if (isTokenRevokedForUser(createdBy)) {
throw new RuntimeException("Token is revoked");
}
if (userRepository.existsByUsername(username)) {
throw new RuntimeException("Username already exists");
}
@@ -124,6 +141,11 @@ public class AuthService {
});
}
@Transactional
public void logoutByUsername(String username) {
tokenRepository.revokeAllUserTokens(username);
}
public boolean isTokenValid(String token) {
return tokenRepository.findByTokenAndRevokedFalse(token).isPresent();
}