1

why spring returns 401 html page instead of my custom json api response with error? and what is the best way to fix it (override spring config)

security:

@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
    return super.authenticationManagerBean();
}

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
            .httpBasic().disable()
            .csrf().disable()
            .cors().disable()
            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
            .authorizeRequests()
            .antMatchers("/v2/api-docs").permitAll()
            .antMatchers("/configuration/ui").permitAll()
            .antMatchers("/swagger-resources/**").permitAll()
            .antMatchers("/configuration/security").permitAll()
            .antMatchers("/swagger-ui.html").permitAll()
            .antMatchers("/swagger-ui/*").permitAll()
            .antMatchers("/webjars/**").permitAll()
            .antMatchers("/v2/**").permitAll()
            .antMatchers(LOGIN_ENDPOINT, REGISTER_ENDPOINT, "/v2/api-docs", "/swagger-ui.html", 
"/v2/swagger-ui.html").permitAll()
            .antMatchers(ADMIN_ENDPOINT).hasRole("ADMIN")
            .anyRequest().authenticated()
            .and()
            .apply(new JwtConfigurer(jwtTokenProvider));
}

Filter:

public class JwtTokenFilter extends GenericFilterBean {
private final JwtTokenProvider jwtTokenProvider;

public JwtTokenFilter(JwtTokenProvider jwtTokenProvider) {
    this.jwtTokenProvider = jwtTokenProvider;
}

@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain filterChain)
        throws IOException, ServletException {

    String token = jwtTokenProvider.resolveToken((HttpServletRequest) req);

    try {
        if (token != null && jwtTokenProvider.isTokenValid(token)) {
            var authentication = jwtTokenProvider.getAuthentication(token);

            if (authentication != null) {
                SecurityContextHolder.getContext().setAuthentication(authentication);
            }
        }
    } catch (JwtAuthenticationException e) {
        SecurityContextHolder.clearContext();
        ((HttpServletResponse) res).sendError(e.getHttpStatus().value());
        ((HttpServletResponse) res).setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        filterChain.doFilter(req, res);
        throw new JwtAuthenticationException("JWT token is expired or invalid", 
HttpStatus.UNAUTHORIZED);
    }
    filterChain.doFilter(req, res);
}
}

so i implemented custom exception handler and filter, and what i need is this type of error

{
   "errorMessage": "Invalid username or password",
   "validationErrors": null
}

that what i get when login fo example, success case to get token is also working

{
"username": "vovaflex",
"token": "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ2b3ZhZmxleCIsInJvbGVzIjpbIlJPTEVfVVNFUiJdLCJpYXQiOjE2MTk4NjQ2MDksImV4cCI6MTYxOTg2ODIwOX0.Oc7AG5ZncfAT3QB8l0mkYDkBr5ZjBfJ2MxLe3M12DF8",
"roles": [
    {
        "id": 1,
        "created": "2021-04-03T18:14:51.891+00:00",
        "updated": "2021-04-03T18:14:51.891+00:00",
        "status": "ACTIVE",
        "name": "ROLE_USER",
        "users": null
    }
]
}

but whey for example token is not correct or expired or so, i get 401 unauthorized (correct) but instead of json with message that i set up i get full html page with error

<!doctype html>
<html lang="en">
<head>
    <title>HTTP Status 401 – Unauthorized</title>
</head>

<body>
    <h1>HTTP Status 401 – Unauthorized</h1>
</body>
</html>

1 Answers1

0

For custom JSON error block, you need to do two things

Implement the AuthenticationEntryPoint.

public class AuthExceptionEntryPoint implements AuthenticationEntryPoint
{
    @Override
    public void commence(
        HttpServletRequest request, 
        HttpServletResponse response, 
        AuthenticationException arg2
    ) throws IOException, ServletException {
        
    }
}

and add that reference in the websecurity settings configure(HttpSecurity http)

@Configuration
@EnableResourceServer
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter
{   
    @Override
    public void configure(HttpSecurity http) throws Exception
    {
        http.exceptionHandling().authenticationEntryPoint(new AuthExceptionEntryPoint()) ;

    }
}

check these two resources for more details

JSON custom authentication

JSON custom error response

rjhdby
  • 1,278
  • 13
  • 15
veritas
  • 378
  • 1
  • 6
  • 16
  • would i be able to use "http.exceptionHandling().authenticationEntryPoint(new AuthExceptionEntryPoint()) ;" from my WebSecurityConfigurerAdapter ? – Vova backend_dev May 01 '21 at 14:57
  • yes, it works on configure method that is overriden from WebSecurityConfigurerAdapter. Here's an implementation below https://www.devglan.com/spring-security/exception-handling-in-spring-security – veritas May 25 '23 at 11:52