Allow CORS with Spring Security 6.1.1 with authenticated requests – Cors

by
Ali Hasan
cors spring-boot spring-security

The Solutions:

Solution 1: Disable CORS headers only for authenticated requests

To allow CORS for all requests, including authenticated ones, modify the CORS configuration to remove the allowCredentials property.

@Bean
CorsConfigurationSource corsConfigurationSource() {
    CorsConfiguration configuration = new CorsConfiguration();
    configuration.addAllowedOriginPattern("*");
    configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"));
    configuration.setAllowedHeaders(Arrays.asList("Authorization", "Content-Type"));
    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    source.registerCorsConfiguration("/**", configuration);
    return source;
}

Next, add a CorsFilter to the security chain to handle CORS requests.

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    http
        .cors(cors -> cors.configurationSource(corsConfigurationSource()))
        .csrf(AbstractHttpConfigurer::disable)
        .authorizeHttpRequests(request -> request
            .requestMatchers("/api/auth/**").permitAll()
            .requestMatchers(SYS_ADMIN_PATTERNS).hasAuthority("SYSTEM_ADMIN")
            .requestMatchers("/api/v1/**").authenticated()
        )
        .addFilterBefore(new CorsFilter(), SecurityContextPersistenceFilter.class) // Add CorsFilter before SecurityContextPersistenceFilter
        .sessionManagement(manager -> manager.sessionCreationPolicy(STATELESS))
        .authenticationProvider(authenticationProvider())
        .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
    return http.build();
}

Additionally, ensure your controllers are annotated with @CrossOrigin to enable CORS for specific endpoints.

@RestController
@RequestMapping("/api/v1")
@CrossOrigin
public class MyController {
    // Controller methods
}

Solution 2: {@link Disable CORS In SecurityFilterChain }

To enable CORS with Spring Security 6.1.1 for authenticated requests, follow these steps:

  1. Disable CORS in the SecurityFilterChain by using cors(AbstractHttpConfigurer::disable):
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    http
        .cors(AbstractHttpConfigurer::disable) // Disable CORS in the SecurityFilterChain
        .csrf(AbstractHttpConfigurer::disable) 
        .authorizeHttpRequests(request -> request
            .requestMatchers("/api/auth").permitAll()
            .requestMatchers(HttpMethod.OPTIONS).permitAll() // Allow OPTIONS requests for preflight requests
            .requestMatchers(SYS_ADMIN_PATTERNS).hasAuthority("SYSTEM_ADMIN")
            .requestMatchers("/api/v1/**").authenticated()
        )
        .sessionManagement(manager -> manager.sessionCreationPolicy(STATELESS))
        .authenticationProvider(authenticationProvider())
        .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
    ;
    SecurityFilterChain chain = http.build();
    log.info("Configured security filter chain: {}", chain);
    return chain;
}
  1. Annotate your REST controllers with @CrossOrigin at the class level or individual method level:
@RestController
@RequestMapping("/api/auth")
@RequiredArgsConstructor
@CrossOrigin
public class AuthenticationController {
    ...
}

This configuration disables CORS in the security filter chain but allows CORS requests for specific endpoints based on the @CrossOrigin annotations.

Solution 4: Configure CORS before Spring Security

To resolve the CORS issue, follow these steps:

  1. Enable CORS default processor:

    .cors(Customizer.withDefaults())
    

    This enables CORS processing before Spring Security.

  2. Configure CORS configuration:
    You can customize CORS behavior using either:

    • Global Configuration
      @Configuration
      @EnableWebSecurity
      public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
      
          @Override
          protected void configure(HttpSecurity http) throws Exception {
              http.cors().configurationSource(corsConfigurationSource());
          }
      
          @Bean
          CorsConfigurationSource corsConfigurationSource() {
              // ...
          }
      }
      
    • CorsWebFilter:
      @Bean
      CorsWebFilter corsWebFilter() {
          // ...
      }
      

Solution 5: Using WebMvcConfigurer

Use the @Component annotation to create a Java class as a Spring bean. Implement the WebMvcConfigurer interface and override the addCorsMappings method. In this method, specify the allowed origins, methods, and headers:

@Component
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("*")
                .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS", "HEAD");
    }
}

Q&A

How to allow CORS with Spring Security 6.1.1 for authenticated requests?

Enable CORS default processor in spring security filter chain and configure CORS configuration globally or using CorsWebFilter.

Why is CORS not working even after following Spring’s documentation?

Ensure that CORS is handled before Spring Security by enabling CORS default processor.

How to allow CORS in Spring Security 6.1.1 for authenticated requests?

Enable CORS globally using WebMvcConfigurer and addCorsMappings method.

Video Explanation:

The following video, titled "Learn Spring Security 6 with Spring Boot 3 | Crash Course | Say ...", provides additional insights and in-depth exploration related to the topics discussed in this post.

Play video

This video will teach how to use Spring Security 6 in Spring Boot 3. I will demonstrate how to remove deprecated APIs, classes, ...