Configure CORS policy for Spring Cloud Gateway

Viewed 6994

I have Spring Cloud gateway running on separate server with the following configuration:

spring:
  cloud:
    gateway:
      globalcors:
        cors-configurations:
          '[/*]':   (I also tried '[/**]':)
            allowedOrigins: "http://localhost:3000"
            allowedMethods:
              - GET
              - POST

But every time from React app I get:

Access to XMLHttpRequest at 'http://11.1.1.1:8080/api/support/tickets/create' from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.

Do you know how this issue an be solved for Spring Boot 2.6.2/Spring cloud 2021.0.0?

Full code: http://www.github.com/rcbandit111/Spring_Cloud_Gateway_POC

POST Request:

Request URL: http://1.1.1.1:8080/api/merchants/onboarding/bank_details
Referrer Policy: strict-origin-when-cross-origin
Accept: application/json, text/plain, */*
Content-Type: application/json
Referer: http://localhost:3000/
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36

Post request Payload:
{"currency":"HNL","iban":"dssvsdvsdv"}

OPTIONS request:

Request URL: http://1.1.1.1:8080/api/merchants/onboarding/bank_details
Request Method: OPTIONS
Status Code: 403 Forbidden
Remote Address: 1.1.1.1:8080
Referrer Policy: strict-origin-when-cross-origin

Response:

HTTP/1.1 403 Forbidden
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
content-length: 0

OPTIONS Request headers:

OPTIONS /api/merchants/onboarding/bank_details HTTP/1.1
Host: 1.1.1.1:8080
Connection: keep-alive
Accept: */*
Access-Control-Request-Method: POST
Access-Control-Request-Headers: content-type
Origin: http://localhost:3000
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36
Sec-Fetch-Mode: cors
Referer: http://localhost:3000/
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
4 Answers

Are you running your FE app via --proxy-conf to redirect? I am not a well versed in FE, but dont use changeOrigin: true. If you have to to use changeOrigin: true, it will only work for GET and for others you might have to do something like this. To use proxy-conf, we usually have a proxy.conf.json with something like this:

{
  "/api/*": {
    "target": "http://external-gateway-url",
    "secure": false,
    "logLevel": "debug"
  }
}

and then while running the app use --proxy-config proxy.conf.json. My FE knowledge is out-of-date. You may want to look something like this.

If not, and the call is direct, just the following configuration (also needed for proxy too) in gateway should work:

spring:
  cloud:
    gateway:
      globalcors:
        corsConfigurations:
          '[/**]':
            allowedOrigins: "http://localhost:3000"
            allowedHeaders: "*"
            allowedMethods:
            - GET
            - POST

I had a similar Problem and i did the following:

My application.yml contains to add the CORS Configuration to every route:

spring:
  cloud:
    gateway:
      globalcors:
        add-to-simple-url-handler-mapping: true

Then I configured a spring standard CorsWebFilter Bean. Note for production you should not use * for the AllowedOrigins property. For Development purpose this is perfectly fine.

@Configuration
public class CorsConfiguration extends org.springframework.web.cors.CorsConfiguration {

  @Bean
  public CorsWebFilter corsFilter() {
    org.springframework.web.cors.CorsConfiguration corsConfiguration = new org.springframework.web.cors.CorsConfiguration();
    corsConfiguration.setAllowCredentials(true);
    corsConfiguration.addAllowedOrigin("*");
    corsConfiguration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS", "HEAD"));
    corsConfiguration.addAllowedHeader("origin");
    corsConfiguration.addAllowedHeader("content-type");
    corsConfiguration.addAllowedHeader("accept");
    corsConfiguration.addAllowedHeader("authorization");
    corsConfiguration.addAllowedHeader("cookie");
    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    source.registerCorsConfiguration("/**", corsConfiguration);
    return new CorsWebFilter(source);
  }
}

Note: I have the Version 2.3.9.Release for spring boot and spring cloud version is Hoxton.SR10 .

Check out the section entitled Simple requests in the MDN Web Docs about CORS:

The only type/subtype combinations allowed for the media type specified in the Content-Type header are:

  • application/x-www-form-urlencoded
  • multipart/form-data
  • text/plain

Because you use the value application/json for your request's Content-Type header, you need to allow that header in your CORS configuration:

cors-configurations:
  '[/**]':
    allowedOrigins: "http://localhost:3000"
    allowedMethods:
      - GET
      - POST
    allowedHeaders:
      - Content-Type

You can add the cors configuration in your security class. Like this

@Configuration
@EnableWebFluxSecurity
public class SecurityConfig {
    private SecurityRepository securityRepository;

    @Bean
    public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http){
        http
                .cors().configurationSource(request -> {
                    CorsConfiguration configuration = new CorsConfiguration();
                    configuration.setAllowedOrigins(List.of("http://localhost:3000"));
                    configuration.setAllowedMethods(List.of("*"));
                    configuration.setAllowedHeaders(List.of("*"));
                    return configuration;
                });
        http.csrf().disable();
        return http.build();
    }
}
Related