Search code examples
spring-bootspring-securitycorsspring-cloud-gateway

Spring Gateway Security Access-Control-Allow-Origin on OPTIONS but not POST


I am having an issue when adding spring security to spring gateway application. I don't know if it's relevant but I am using spring-boot-starter-parent 2.5.8.

I created the gateway app initially without the spring security to test that the routing was working to another api using it's eureka url. This worked fine. 200 response received with this configuration:

@Configuration
public class RouterConfig {
    @Bean
    public RouteLocator routes(RouteLocatorBuilder builder) {
        return builder.routes()
                .route("account", r -> r
                        .path("/account/**")
                        .filters(f -> f.stripPrefix(1).prefixPath("/java-app-account/v1"))
                        .uri("lb://JAVA-APP-ACCOUNT")
                        
                    )
                
                .build();
    }
}

So when I added spring boot security obviously CORS kicks in with a 403 forbidden error so I add the following configurations:

@Configuration
@EnableConfigurationProperties(value = {GlobalCorsProperties.class})
public class SpringSecurityConfig {
     @Bean
      SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) throws Exception {
        http
                .authorizeExchange()
                .pathMatchers(HttpMethod.OPTIONS,"/account/**").permitAll()
                 .pathMatchers(HttpMethod.POST,"/account/**").permitAll()
                 ;
        return http.build();
      }
}

AND

public class CustomCorsConfiguration {

    @Bean
    public WebFilter corsFilter() {
        return (ServerWebExchange ctx, WebFilterChain chain) -> {
            ServerHttpRequest request = ctx.getRequest();
            if (CorsUtils.isCorsRequest(request)) {
                ServerHttpResponse response = ctx.getResponse();
                HttpHeaders headers = response.getHeaders();
                headers.add("Access-Control-Allow-Origin", "http://localhost:4200");
                headers.add("Access-Control-Allow-Methods", "GET, PUT, POST, DELETE, OPTIONS, PATCH");
                headers.add("Access-Control-Max-Age", "7200"); 
                headers.add("Access-Control-Allow-Headers",
                        "x-requested-with, authorization, Content-Type, Content-Length, Authorization, credential, X-XSRF-TOKEN");
                if (request.getMethod() == HttpMethod.OPTIONS) {
                    response.setStatusCode(HttpStatus.OK);
                    return Mono.empty();
                }
            }
            return chain.filter(ctx);
        };
    }
}

The problem I have is, the preflight OPTIONS request returns the header Access-Control-Allow-Headers but the POST is rejected with Forbidden error with no header in the response.

What have I missed here?


Solution

  • CSRF filter was stopping the request before the CORS filter was able to add the headers. disabling CSRF protection solves the issue. I will add the CSRF protection and make sure the token is now passed.