I am developing a Spring Boot 3 application with Spring Security 6, and I need to customize the error messages for invalid API keys. When an invalid API key is provided, I want the error message “Invalid API Key” to be returned instead of the default “Full authentication is required to access this resource.”
Here are the classes I have implemented so far:
@Component
public class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint {
private final ObjectMapper objectMapper = new ObjectMapper();
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException {
response.setStatus(HttpStatus.UNAUTHORIZED.value());
response.setContentType("application/json");
Map<String, Object> data = new HashMap<>();
data.put("message", authException.getMessage());
data.put("error", HttpStatus.UNAUTHORIZED);
response.getOutputStream().println(objectMapper.writeValueAsString(data));
}
}
@Component
public class ApiKeyAuthFilter extends OncePerRequestFilter {
private static final Logger LOGGER = Logger.getLogger(ApiKeyAuthFilter.class.getName());
private static final String API_KEY_HEADER = "X-API-KEY";
private static final String VALID_API_KEY = "valid-api-key";
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException, ApiKeyAuthenticationException {
String apiKey = request.getHeader(API_KEY_HEADER);
LOGGER.info("API Key received: " + apiKey);
if (VALID_API_KEY.equals(apiKey)) {
UserDetails userDetails = User.withUsername("apiKeyUser")
.password("")
.authorities(Collections.emptyList())
.build();
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authentication);
LOGGER.info("Authentication set in security context");
} else {
throw new ApiKeyAuthenticationException("Invalid API Key");
}
filterChain.doFilter(request, response);
}
}
public class ApiKeyAuthenticationException extends AuthenticationException {
public ApiKeyAuthenticationException(String message) {
super(message);
}
}
@Configuration
@EnableWebSecurity
public class SecurityConfig {
private final CustomAuthenticationEntryPoint customAuthenticationEntryPoint;
public SecurityConfig(CustomAuthenticationEntryPoint customAuthenticationEntryPoint) {
this.customAuthenticationEntryPoint = customAuthenticationEntryPoint;
}
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.csrf(csrf -> csrf.disable())
.sessionManagement(sessionManagement ->
sessionManagement.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeHttpRequests(authorizeRequests ->
authorizeRequests.anyRequest().authenticated())
.addFilterBefore(new ApiKeyAuthFilter(), BasicAuthenticationFilter.class)
.exceptionHandling(exceptionHandling ->
exceptionHandling.authenticationEntryPoint(customAuthenticationEntryPoint));
return http.build();
}
}
Despite these implementations, the error message returned is still the default “Full authentication is required to access this resource.”
How can I ensure that the custom error message “Invalid API Key” is returned when an invalid API key is provided?
Thank you for your help!