package com.ankurm.jwtauth.config; import java.net.URI; import org.springframework.http.HttpStatus; import org.springframework.http.ProblemDetail; import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.authentication.DisabledException; import org.springframework.security.authentication.LockedException; import org.springframework.security.core.AuthenticationException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; /** * Login failures arrive here, not at the {@code AuthenticationEntryPoint} - the * controller calls {@code AuthenticationManager} itself, so the exception is a plain * MVC exception by the time anything security-shaped could see it. * *

Note every branch answers 401 with the same body. Telling a caller that the * username exists but the password is wrong is a user-enumeration oracle. */ @RestControllerAdvice public class ApiExceptionHandler { @ExceptionHandler({BadCredentialsException.class, LockedException.class, DisabledException.class}) public ProblemDetail onAuthenticationFailure(AuthenticationException ex) { ProblemDetail problem = ProblemDetail.forStatus(HttpStatus.UNAUTHORIZED); problem.setType(URI.create("https://ankurm.com/problems/invalid-credentials")); problem.setTitle("Authentication failed"); problem.setDetail("Invalid username or password"); return problem; } @ExceptionHandler(AuthenticationException.class) public ProblemDetail onAuthentication(AuthenticationException ex) { ProblemDetail problem = ProblemDetail.forStatus(HttpStatus.UNAUTHORIZED); problem.setTitle("Authentication failed"); problem.setDetail("Invalid username or password"); return problem; } }