authenticationspring-securitypermission-denied

authentication fails with Spring Security with "permitAll"


I configured Spring Security in order to have some api protected and other publicly available, and it works. However, if for some reason a public api is called with the "Authorization" header, the access is denied. How can I avoid this behavior and give complete access to that API regardless of the presence of the "Authorization" header in the request?

Here is my configuration:

@Bean
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
  http.authorizeHttpRequests(auth -> auth
      .requestMatchers(HttpMethod.GET, "/api/public").permitAll()
      .requestMatchers(HttpMethod.GET, "/api/*").authenticated()
  )
  .httpBasic(Customizer.withDefaults())
  .headers(
    headers -> headers
      .frameOptions(
        HeadersConfigurer.FrameOptionsConfig::sameOrigin)
        .contentSecurityPolicy(
          csp -> csp.policyDirectives(
            "default-src 'self'; " +
            "style-src 'self' 'unsafe-inline'; " +
            "script-src 'self'; " +
            "form-action 'self'; " +
            "connect-src 'self'; " +
            "frame-src 'self'; " +
            "frame-ancestors 'self'; " +
            "font-src 'self'; " +
            "media-src 'self'; " +
            "object-src 'self'; " +
            "manifest-src 'self';"
          )
      )
  );
  return http.build();
}


Solution

  • The issue you're facing is due to a security filter treating the presence of an Authorization header as an intent to authenticate, even for endpoints explicitly marked with .permitAll()

    You need to customize the security configuration to skip authentication filters for public endpoints, even when Authorization is present.

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {
    
        String path = request.getRequestURI();
    
        if (path.startsWith("/api/public")) {
            filterChain.doFilter(request, response);
            return;
        }
    
    }