cloudwalker cloudwalker - 9 months ago 174
reST (reStructuredText) Question

Spring Boot REST API/Spring Security: Return custom message when authentication fails

I have a Spring Boot app using Jersey as the JAX-RS implementation. This is my security configuration:

@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

@Autowired TokenAuthenticationProvider tokenAuthenticationProvider;

public void configure(AuthenticationManagerBuilder auth) throws Exception {

protected void configure(HttpSecurity http) throws Exception {
http.addFilterBefore(new AuthenticationTokenFilter(), BasicAuthenticationFilter.class)

What I want to be able to do is to have a way to catch the Exceptions thrown by my TokenAuthenticationProvider and convert them into a standardized JSON format that we have agreed upon. Is there a way to do this? I tried messing around with adding a custom AuthenticationFailureHandler, but couldn't get that to work.

Answer Source

WebSecurityConfigurerAdapter appraoch

The HttpSecurity class has a method called exceptionHandling which can be used to override the default behavior. The following sample presents how the response message can be customized.

protected void configure(HttpSecurity http) throws Exception {
        // your custom configuration goes here
        .authenticationEntryPoint((request, response, e) -> {
            String json = String.format("{\"message\": \"%s\"}", e.getMessage());

@ControllerAdvice appraoch - Why it doesn't work in this case

At first I thought about @ControllerAdvice that catches authentication exceptions for the entire application.

import org.springframework.http.HttpStatus;

public class AuthExceptionHandler {

    public String handleAuthenticationException(AuthenticationException e) {
        return String.format("{\"message\": \"%s\"}", e.getMessage());


In the example above, the JSON is built manually, but you can simply return a POJO which will be mapped into JSON just like from a regular REST controller. Since Spring 4.3 you can also use @RestControllerAdvice, which is a combination of @ControllerAdvice and @ResponseBody.

However, this approach doesn't work because the exception is thrown by the AbstractSecurityInterceptor and handled by ExceptionTranslationFilter before any controller is reached.