Summary

Why do I get an HTTP status code 401 with a RESTful API with basic authentication by executing an HTTP POST (csrf enabled). I would expect an 403 status code as the AccessDeniedHandlerImpl write in the log. But the request ist "redirected" to /error an the BasicAuthenticationFilter is not jet executet and the AuthenticationEntryPoint wirte an status 401 with an authentication header. The user is an valid authenticated user, but tries to POST a request without csrf token.

Actual Behavior

Client side receives 401 status code instead of 403

Expected Behavior

Client side receives 403 status code instead of 401

Configuration

see sample

Version

6.01 RELEASE

Sample

@Configuration
@EnableWebSecurity(debug = true)
public class WebSecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.authorizeHttpRequests().anyRequest().authenticated();
        http.httpBasic(withDefaults());
        //Session management
        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
        //Security header setting (disable csrf and set sameOrigin)
        return http.build();
    }
}
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder(12);
    }

    @Bean
    public UserDetailsService inMemoryUsers() {
        UserDetails user1 = User.builder()
                .username("customer@bfh.ch")
                .password(passwordEncoder().encode("12345678"))
                .roles(Constants.CUSTOMER)
                .build();
        UserDetails user2 = User.builder()
                .username("employee@bfh.ch")
                .password(passwordEncoder().encode("12345678"))
                .roles(Constants.EMPLOYEE)
                .build();
        UserDetails admin = User.builder()
                .username("admin@bfh.ch")
                .password(passwordEncoder().encode("87654321"))
                .roles(Constants.ADMINISTRATOR)
                .build();
        return new InMemoryUserDetailsManager(user1, user2, admin);
    }

    @GetMapping(path = "/token")
    public String getToken(Authentication authentication) {
        return "123456";
    }

Comment From: marcusdacoregio

Hi @pitFromCH,

The CsrfFilter is executed before the BasicAuthenticationFilter, therefore there will be no request authentication yet. In the ExceptionTranslationFilter, if the authentication is not present, instead of executing the AccessDeniedHandler, Spring Security calls the AuthenticationEntryPoint. That's why you are seeing a 401 instead of 403.

I'm closing this as it seems to be more suited for Stackoverflow, however, you can continue the discussion if you think there is something off.