title: Configuring Spring Security (two-way SSL) to not require authentication only on CORS preflight OPTIONS requests
body: <p>I've been on a witch hunt of trying to figure out why cross-origin requests fail only in Firefox.  Turns out Firefox does not send SSL/TLS credentials on cross-origin XHRs, which apparently is defined by the <a href="https://fetch.spec.whatwg.org/#cors-preflight-fetch" rel="nofollow noreferrer">W3 CORS Spec</a>.  I was able to <em>mostly</em> resolve this by adding a <code>withCredentials: true</code> to my XHR instances in my client code (it works for GET, PUT, POST, DELETE, etc.).</p>
  
  <p>However, Firefox still refuses to add credentials to pre-flight OPTIONS requests despite me explicitly telling it to in the XHR.  Unless there is somehow a way to do this in client code, I am left with configuring my server to allow un-authenticated OPTIONS requests (which in a 2-way SSL configuration seems insane to me).  Are there security risks here?</p>
  
  <p>Our server is a Spring Boot project that uses Spring Security, and is configured for 2-way SSL using X509 security certificates.  I will provide all relative code to give you an idea of how the application is configured.</p>
  
  <p>Main class:</p>
  
  <pre><code>@EnableAutoConfiguration
  @SpringBootApplication
  @EnableWebSecurity
  @EnableGlobalMethodSecurity(prePostEnabled = true)
  public class OurApp extends WebSecurityConfigurerAdapter {
  
      @Autowired
      OurUserDetailsService ourUserDetailsService;
  
      public static void main(String[] args) throws Exception {
          ConfigurableApplicationContext ctx = SpringApplication.run(OurApp.class, args);
      }
  
      @Override
      public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers(HttpMethod.OPTIONS, "/**");
      }
  
      @Override
      protected void configure(HttpSecurity http) throws Exception {
          // X509Configurer&lt;HttpSecurity&gt; x509Configurer = http.authorizeRequests().anyRequest().authenticated().and().x509();
  
          http.authorizeRequests().antMatchers(HttpMethod.OPTIONS, "/**").permitAll().
              .anyRequest().authenticated()
              .and()
              .x509().subjectPrincipalRegex("(.*)").authenticationUserDetailsService(ourUserDetailsService)
              .and()
              .cors()
              .and()
              .csrf().disable();
      }
  }
  </code></pre>
  
  <p>Configuration class that has CORS setup:</p>
  
  <pre><code>@Configuration
  public class OurConfig {
      @Bean
      public CorsConfigurationSource corsConfigurationSource() {
          CorsConfiguration configuration = new CorsConfiguration();
          configuration.setAllowedOrigins(Arrays.asList("https://client-origin"));
          configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "PATCH", "DELETE", "HEAD"));
          configuration.setAllowedHeaders(Arrays.asList("Authorization", "Content-Type", "Access-Control-Allow-Origin",
              "Access-Control-Allow-Headers", "X-Requested-With", "requestId", "Correlation-Id"));
          configuration.setAllowCredentials(true);
          UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
          source.registerCorsConfiguration("/**", configuration);
          return source;
      }
  
      @Bean
      public IgnoredRequestCustomizer optionsIgnoredRequestsCustomizer() {
        return configurer -&gt; {
          List&lt;RequestMatcher&gt; matchers = new ArrayList&lt;&gt;();
          matchers.add(new AntPathRequestMatcher("/**", "OPTIONS"));
          configurer.requestMatchers(new OrRequestMatcher(matchers));
        };
      }
  }
  </code></pre>
  
  <p>This WORKS on all GET requests, and when I manually perform the requests in browser for the other verbs -- except for OPTIONS.  The preflight request continues to fail during the TLS handshake and is aborted by Firefox.  I'm confused, is it even possible to send an un-authenticated (credential-less) request over (two-way SSL) HTTPS?  </p>
  
  <p>How do I configure spring security or spring boot to allow unauthenticated OPTIONS requests with a two-way SSL (over HTTPS) enabled configuration?</p>