Spring Boot CORS filter - CORS preflight channel did not succeed

79,337

Solution 1

I have fixed this issue by creating a new CORS Filter:

@Component
public class CorsFilter extends OncePerRequestFilter {

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers", "authorization, content-type, xsrf-token");
        response.addHeader("Access-Control-Expose-Headers", "xsrf-token");
        if ("OPTIONS".equals(request.getMethod())) {
            response.setStatus(HttpServletResponse.SC_OK);
        } else { 
            filterChain.doFilter(request, response);
        }
    }
}

and added it to securty configuration:

.addFilterBefore(new CorsFilter(), ChannelProcessingFilter.class)

UPDATED - More modern way nowadays which I switched to:

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        http
            .cors()
        .and()

        ...
    }

    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(Arrays.asList("*"));
        configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"));
        configuration.setAllowedHeaders(Arrays.asList("authorization", "content-type", "x-auth-token"));
        configuration.setExposedHeaders(Arrays.asList("x-auth-token"));
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }

}

Solution 2

Had the same issue getting CORS to work with spring data rest, this was the filter code I used.

    /**
 * Until url{https://jira.spring.io/browse/DATAREST-573} is fixed
 * 
 * @return
 */
@Bean
public CorsFilter corsFilter() {

    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    CorsConfiguration config = new CorsConfiguration();
    //config.setAllowCredentials(true); // you USUALLY want this
    config.addAllowedOrigin("*");
    config.addAllowedHeader("*");
    config.addAllowedMethod("OPTIONS");
    config.addAllowedMethod("HEAD");
    config.addAllowedMethod("GET");
    config.addAllowedMethod("PUT");
    config.addAllowedMethod("POST");
    config.addAllowedMethod("DELETE");
    config.addAllowedMethod("PATCH");
    source.registerCorsConfiguration("/**", config);
    return new CorsFilter(source);
}

Solution 3

This is very simple and working well. Within the class you wrote for Web Security Configurations, enter this line httpSecury.cors();


@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {


    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {

         httpSecurity.cors();     //  This enables cors

        // Your codes

    }

}


Solution 4

I still had the CORS error after following the two tutorials:

First I followed the Web Security guide: https://spring.io/guides/gs/securing-web/#scratch

Second I followed the CORS guide: https://spring.io/guides/gs/rest-service-cors/#global-cors-configuration

To resolve my issues after following these guides I had to add http.cors() to the http security.

@Override
protected void configure(HttpSecurity http) throws Exception {
  http.cors()
  .and()
    ...
} 

Adding the .cors() allows it to use the @Bean I declared for my CORS configuration.

@Bean
public WebMvcConfigurer corsConfigurer() {
  return new WebMvcConfigurer() {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
      registry.addMapping("/**").allowedOrigins("http://localhost:4200");
    }
  };
}

Solution 5

For what its worth, the following combination solution worked for me:

1.

@Configuration
public class CorsConfiguration {

//This can be used in combination with @CrossOrigin on the controller & method.

    @Bean
    public WebMvcConfigurer corsConfigurer() {
        return new WebMvcConfigurerAdapter() {
            @Override
            public void addCorsMappings(CorsRegistry registry) {
                registry.addMapping("/**")
                        .allowedMethods("HEAD","OPTIONS")
                        .allowedHeaders("Origin", "X-Requested-With", "Content-Type", "Accept");
            }
        };
    }
}

2. @CrossOrigin on the RestController class. Having @CrossOrigin reads the @RequestMapping annotations and the HTTP methods in it. Rest of the requests are rejected with CORS error.

But you will be out of luck with the above solution if you want to use spring security in your project.

I am using spring boot version 1.5.4.RELEASE.

Share:
79,337
alexanoid
Author by

alexanoid

Updated on July 09, 2022

Comments

  • alexanoid
    alexanoid almost 2 years

    I need to add CORS filter to my Spring Boot web application.

    I have added CORS mappings as described in the following documentation http://docs.spring.io/spring/docs/current/spring-framework-reference/html/cors.html

    This is my config:

    @Configuration
    @EnableWebMvc
    public class WebMvcConfig extends WebMvcConfigurerAdapter {
    
        @Override
        public void addCorsMappings(CorsRegistry registry) {
            // @formatter:off   
            registry
                .addMapping("/**")
                .allowedOrigins(CrossOrigin.DEFAULT_ORIGINS)
                .allowedHeaders(CrossOrigin.DEFAULT_ALLOWED_HEADERS)
                .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
                .maxAge(3600L);
            // @formatter:on
        }
    
    ...
    
    }
    

    Right now when I'm trying to access my API I receiving a following error:

    Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://example.com/api/v1.0/user. (Reason: CORS preflight channel did not succeed).
    

    This is a screenshot from FF console:

    enter image description here

    What am I doing wrong and how to properly configure CORS headers in order to avoid this issue ?

  • Алексей Романов
    Алексей Романов about 8 years
    At the beginning leave only required http methods in allowed methods. Then try make raw request using curl curl -H "Origin: http://127.0.0.1" --verbose http://127.0.0.1/api/v1.0/user. You have to see Access-Control-Allowed-* headers in response. And finally, try to specify you host (127.0.0.1 or smth. else) in AllowedOrigin.
  • alexanoid
    alexanoid about 8 years
    I have tried allowedHeaders("xsrf-token").exposedHeaders("xsrf-token") but still doesn't working. I think I need something like this - if ("OPTIONS".equals(request.getMethod())) { response.setStatus(HttpServletResponse.SC_OK); } but I don't know how to add this logic into CorsRegistry registry
  • Marco Tedone
    Marco Tedone about 8 years
    If you want to support proper RESTful APIs, shouldn't you add also the PUT verb in there?
  • Nadeem Jamali
    Nadeem Jamali almost 6 years
    I used the above example code and others too, but none of them worked on the application level. Eventually, I set the CORS over controller level.
  • Maciek Kreft
    Maciek Kreft almost 6 years
    It's best configuration, because it works not only for controllers but also for interceptors! Thx!
  • Davut Gürbüz
    Davut Gürbüz over 5 years
    Our project is not MVC and your not updated solution helped.
  • Sebastiandg7
    Sebastiandg7 about 5 years
    @alexanoid Does the last option using the CorsConfigurationSource allows to dynamically load the allowed domains from, for example, a database? Use case: an admin web app where you can control the allowed domains for your application.
  • Bằng Rikimaru
    Bằng Rikimaru almost 5 years
    This is the only configuration which can work with $http.get in AngularJs 1.6 and I found this after hours of trying with no understand about why
  • Glenn
    Glenn over 4 years
    You know, I like Spring, but CORS configuration has been causing me no end of grief. Everytime I upgrade my Springboot version, CORS is broken again for my REST app. My filter isn't being picked up. It isn't at the top. Doesn't work if you included spring-data. Always something. For the last round, this helped me for my oauth token retrieval, but I still had to keep a filter to handle the OPTIONS pre-flight: if ("OPTIONS".equalsIgnoreCase(request.getMethod())) { response.setStatus(HttpServletResponse.SC_OK); }
  • Henry
    Henry over 4 years
    Sorry but where do you place the above code in? Or do I need to create a new class filter and create the above Bean inside the new class?
  • Romell
    Romell over 4 years
    The code is placed in any class that has the @Configuration annotation but there are easier ways to do this with Spring Boot 2, see comments further down the page
  • rineez
    rineez almost 4 years
    Documentations and forum posts everywhere was giving same procedure but none of them mentioned this requirement to call http.cors() inside the void configure(HttpSecurity http) implementation. I'm really thankful because this fixed my problem ultimately after a long struggle. Is this actually documented somewhere?
  • rineez
    rineez almost 4 years
    I had to do this inside my class with @EnableWebSecurity annotation, that extends WebSecurityConfigurerAdapter. (I guess it will may be a direct implementation of WebSecurityConfigurer<WebSecurity> interface for some others)
  • seedme
    seedme about 2 years
    if you are using spring-boot-starter-web this seems the simplest way of configuring it. mind to further notate .allowedOrigins and .allowedHeaders in production.