Spring Security exception handling return HTTP status 401 instead of 403
- Details
- Written by Nam Ha Minh
- Last Updated on 05 July 2024   |   Print Email
When developing REST APIs with the Spring framework and Spring Security, you may encounter a situation where the client provides invalid credentials but the server returns HTTP status 403 Forbidden, which incorrectly conveys the meaning of the error to the client. In such cases, the server should return HTTP status 401 Unauthorized, which better reflects the nature of the error because:
- HTTP status 403 (Forbidden) indicates that the server understood the request but refuses to authorize it. This status code is used when the client’s credentials are recognized (the user is authenticated), but the client does not have permission to access the resource.
- HTTP status 401 (Unauthorized) indicates that the client must authenticate itself to get the requested response. This status code is used when the client has not provided credentials, or the provided credentials are invalid.
So, to fix this issue in Spring Security, put the following code in your security configuration class (with Spring Security 5.x or earlier):
@Configuration public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() ... .and() .exceptionHandling().authenticationEntryPoint( (request, response, ex) -> { response.sendError(HttpServletResponse.SC_UNAUTHORIZED, ex.getMessage()); } ); } }
This code ensures that when an authentication error occurs, the application will send HTTP status 401 to the client.
With Spring Security 6.x or later, the configuration code will be slightly different, as shown below:
@Configuration public class SecurityConfig { @Bean SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http.authorizeHttpRequests(...) .exceptionHandling(exh -> exh.authenticationEntryPoint( (request, response, ex) -> { response.sendError(HttpServletResponse.SC_UNAUTHORIZED, ex.getMessage()); } )) return http.build(); } }
Note that the authenticationEntryPoint() method accepts an object of a class that implements the AuthenticationEntryPoint interface, which declares the following method:
void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException;
That means the above configuration code uses Lambda expression as a shortcut to create a class that implement the functional interface AuthenticationEntryPoint. Got it?
That’s how to update Spring Security configuration to return HTTP status 401 instead of 403 in case authentication error occurs, which better reflects the meaning of the status code to the client. I recommend you watch the following video to see the coding in a real-life project:
Related Spring Security Articles:
- Spring Security permit all requests
- Spring security allow static resources
- How to disable CSRF in Spring Security
Learn more about Spring Security:
- Spring Security Registration and Login Tutorial
- Spring Security Role-based Authorization Tutorial
- Spring Security Remember Me Examples
- Spring Security Forgot Password Tutorial
- Spring Security Social Login with Google and Facebook
- Full Spring Security Tutorials List
Comments