Summary: Spring Security only detects a CorsConfigurationSource bean by name "corsConfigurationSource", causing silent CORS failures when the bean name differs.

Describe the bug

When using .cors(Customizer.withDefaults()) in Spring Security configuration, the framework looks for a bean with the exact name "corsConfigurationSource". If a CorsConfigurationSource bean is registered with a different name (e.g., when using @Profile annotations with different method names), Spring Security silently falls back to DefaultCorsProcessor, which rejects all preflight requests by default.

This leads to "Invalid CORS request" errors without any warning or error message during bean registration, which can be confusing since no warning or error is logged.

To Reproduce

Steps to reproduce the behavior:

  1. Create a SecurityConfig with profile-specific CORS configurations:
@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
@Slf4j
public class SecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
                .cors(Customizer.withDefaults())  // Uses auto-configuration
                // ... other configurations

        return http.build();
    }

    @Bean
    @Profile("prod")
    public CorsConfigurationSource corsConfigurationSource() {
        // Production CORS config
    }

    @Bean
    @Profile("!prod")
    public CorsConfigurationSource testCorsConfigurationSource() {  // Different bean name!
        CorsConfiguration config = new CorsConfiguration();

        config.setAllowedOrigins(List.of("*"));
        config.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"));
        config.setAllowedHeaders(List.of("*"));
        config.setAllowCredentials(false);

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", config);
        return source;
    }
}
  1. Run the application with a non-prod profile (e.g., test)
  2. Make an OPTIONS preflight request
  3. Observe "Invalid CORS request" error

Root Cause

In CorsConfigurer.getCorsFilter():

private CorsFilter getCorsFilter(ApplicationContext context) {
    if (this.configurationSource != null) {
        return new CorsFilter(this.configurationSource);
    }
    boolean containsCorsFilter = context.containsBeanDefinition(CORS_FILTER_BEAN_NAME);
    if (containsCorsFilter) {
        return context.getBean(CORS_FILTER_BEAN_NAME, CorsFilter.class);
    }
    boolean containsCorsSource = context.containsBean(CORS_CONFIGURATION_SOURCE_BEAN_NAME);  // Looks for "corsConfigurationSource"
    if (containsCorsSource) {
        CorsConfigurationSource configurationSource = context.getBean(CORS_CONFIGURATION_SOURCE_BEAN_NAME,
                CorsConfigurationSource.class);
        return new CorsFilter(configurationSource);
    }
    // Falls back to MVC CORS or null
}

The framework only looks for a bean named "corsConfigurationSource" (the CORS_CONFIGURATION_SOURCE_BEAN_NAME constant). When the bean name is different, it's not detected, and DefaultCorsProcessor is used instead.

DefaultCorsProcessor rejects preflight requests when no configuration is found:

boolean preFlightRequest = CorsUtils.isPreFlightRequest(request);
if (config == null) {
    if (preFlightRequest) {
        rejectRequest(new ServletServerHttpResponse(response));
        return false;
    }
    else {
        return true;
    }
}

Expected behavior

One of the following should happen:

Option 1: When using .cors(Customizer.withDefaults()), if multiple beans of type CorsConfigurationSource exist, Spring Security should:

  1. Prefer a bean named corsConfigurationSource
  2. Otherwise, use the only available bean of that type
  3. Fail-fast if multiple candidates exist

This would be more intuitive and consistent with Spring's general dependency injection behavior.

Option 2: If the current behavior is intentional, the framework should: - Log a clear warning when no corsConfigurationSource bean is found but other CorsConfigurationSource beans exist - Throw an exception during startup when CORS is enabled but no valid configuration source is detected - Improve documentation to explicitly mention the required bean name

Workaround

Current workarounds:

  1. Explicitly set the bean name: @Bean(name = "corsConfigurationSource")
  2. Inject the bean explicitly: .cors(cors -> cors.configurationSource(corsConfigurationSource))

Sample

Sample Porject Here

The test CorsIssueTest.testPreflightRequestFails() will fail with a 403 Forbidden error, demonstrating the bug.

Full documentation and reproduction steps are available in the sample project's README.md.

Additional Context

This issue particularly affects developers who: - Use Spring profiles to configure different CORS policies per environment - Follow naming conventions that differ from the default bean name - Expect Spring's type-based dependency injection to work consistently

The lack of any error message or warning during bean initialization makes this issue time-consuming to debug.

🙋‍♂️ Contribution

I'm open to preparing a pull request once the team confirms the preferred approach.

Comment From: rwinch

Thank you for reporting your concern and providing such a great sample!

Spring Security only detects a CorsConfigurationSource bean by name "corsConfigurationSource", causing silent CORS failures when the bean name differs. ... Spring Security silently falls back to DefaultCorsProcessor, which rejects all preflight requests by default.

CorsProcessor and CorsConfigurationSource are two different things & Spring Security's default setup does not ever change the CorsProcessor.

That said, Spring Security is not failing silently, but using the CorsConfigurationSource published by Spring MVC. Spring Security uses a named bean so that applications can easily override the CorsConfigurationSource by bean name in Spring MVC application if they so desire. However, the most typical setup for CORS is using Spring Security with Spring MVC's CORS configuration.

If the application is not using Spring MVC and does not publish a Bean with the name corsConfigurationSource then an Exception is thrown.