Search code examples
javaspring-bootswaggerspring-cloudspring-cloud-gateway

Spring gateway swagger configuration CORS


I have two services: user service and logic service, and spring gateway to access them. Both of my services have spring security configured, that requires JWT token on some methods. On my logic microservice I configured springdoc-openapi-starter-webmvc-ui swagger dependency like this:

@Configuration
@SecurityScheme(
    name = "bearerAuth",
    type = SecuritySchemeType.HTTP,
    bearerFormat = "JWT",
    scheme = "bearer"
)
public class OpenApiConfiguration {

}

And then added on my controllers (note that CrossOrigin already here):

@CrossOrigin
@SecurityRequirement(name = "bearerAuth")
public class LogicController {
...
}

In swagger I can see what paths are protected, what not. And I can call them with valid JWT token, it's all works just fine from microservice swagger directly. The problem is with spring gateway swagger. I configured paths like this:

spring:
  cloud:
    gateway:
      default-filters:
        - DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin
      globalcors:
        corsConfigurations:
          '[/**]':
            allowedOrigins: "*"
            allowedMethods: "*"
            allowedHeaders: "*"
      routes:
        - id: logic-service
          uri: lb://LOGIC-SERVICE
          predicates:
            - Path=/api/logic/**
        - id: user-manager
          uri: lb://USER-MANAGER
          predicates:
            - Path=/user-manager/**
            - Path=/other-api/**
        - id: logic-service-swagger
          uri: lb://LOGIC-SERVICE
          predicates:
            - Path=/logic/v3/api-docs
        - id: user-manager-swagger
          uri: lb://USER-MANAGER
          predicates:
            - Path=/user/v3/api-docs

springdoc:
  api-docs:
    enabled: true
  swagger-ui:
    enabled: true
    path: /swagger-ui.html
    config-url: /v3/api-docs/swagger-config
    urls:
      - url: /logic/v3/api-docs
        name: Logic service
      - url: /user/v3/api-docs
        name: Users service

I'm using these dependencies on my gateway:

 <dependencies>
    <dependency>
      <groupId>org.springdoc</groupId>
      <artifactId>springdoc-openapi-starter-webflux-ui</artifactId>
      <version>2.1.0</version>
    </dependency>
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-gateway</artifactId>
    </dependency>
 <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>

Swagger paths are correct, I can open the gateway swagger and choose between 2 of my services, Eureka is working, services are registered, this is not a problem. I can perform public methods, but can't call methods that are secured with token. The requests from gateway swagger are getting sent with correct authorization header. As I said same request is working on the swagger microservice directly.
For example, if I open logic microservice swagger on 8081 port, click on authorize button in swagger and perform request, it's working fine. But when I do the same on 8080 gateway port, it's giving me cors error:

Failed to fetch.
Possible Reasons:
CORS
Network Failure
URL scheme must be "http" or "https" for CORS request.

The curl that is getting generated is the same both on logic microservice swagger and on gateway swagger, i.e. even from gateway swagger the curl generated is using 8081 port of logic microservice. But it was working fine before I added JWT security configuraton to the logic service. If I make a generated curl call to both 8080 (gateway) and 8081 (directly), they both send me a normal response (the same curl is working if I change port to 8080 i.e. gateway port):

curl -X 'GET' \
  'http://localhost:8081/api/logic/...' \
  -H 'accept: */*' \
  -H 'Authorization: Bearer token...'

I already tried to add this, as it was suggested in another answer:

default-filters:
        - DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin
      globalcors:
        corsConfigurations:
          '[/**]':
            allowedOrigins: "*"
            allowedMethods: "*"
            allowedHeaders: "*"

But it's not working. Setting level to debug on gateway also doesn't help, nothing is getting logged. Can someone help me out?


Solution

  • Okay, so turns out you also need to add cors in security configuration on microservice itself:

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

    Thanks to this answer