0

Accessing API from browser (a jQuery script) is getting blocked. Here is the error message I am getting:

Access to XMLHttpRequest at 'http://localhost:8765/conversion/convert' from origin 'null' 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.

My jQuery script in a HTML file:

$.ajax({
    type: 'POST',
    url: 'http://localhost:8765/conversion/convert',
    headers: {
        'Content-Type': 'application/json',
        'Authorization': 'Bearer MY_JWT_TOKEN'
    },
    data: JSON.stringify({
        id: 1,
        from: 'usd',
        to: 'bdt',
        quantity: 100
    }),
    success: function(data) {
        console.log(data);
    },
    error: function(error) {
        console.error(error);
    }
});

Maven Dependencies and Versions:

  1. spring-cloud-gateway: 2022.0.4
  2. spring-cloud-starter-gateway: 3.1.6
  3. spring-boot-starter-oauth2-resource-server: 3.1.6
  4. spring-cloud-starter-netflix-eureka-client

I have configured OAuth2 (Keycloak) with my API gateway and used CORS (globalcors) config in my Gateway service config file (yml) as directed on official Spring Cloud page. I also tried all the different approaches from internet, nothing seems working.

spring:
  security:
    oauth2:
      resourceserver:
        jwt:
          issuer-ui: http://localhost:9000/realms/Microservices-demo-realm
          jws-algorithm: RS256
  cloud:
    gateway:
      globalcors:
        cors-configurations:
          '[/**]':
            allowedOrigins: "*"
            allowedMethods: "*"
            allowedHeaders: "*"
      default-filters:
        - DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin RETAIN_UNIQUE
        - name: TokenRelay
      routes:
        - id: conversion-service
          uri: lb://currency-conversion
          predicates:
            - Path=/conversion/**

Here is the Google Chrome Network Console:

enter image description here

I have also tried from a tiny ReactJS app and CORS are being block from there as well. Here is a screenshot:

enter image description here

Please help!

3
  • CORS warnings are just a side-effect of the 401 response code. Your app needs to handle pre-flight OPTIONS requests outside of any authentication requirements Commented Dec 11, 2023 at 4:22
  • @Phil Thanks a lot for the hint. It worked for me. This is the working example: @Bean public SecurityWebFilterChain filterChain(ServerHttpSecurity http) { http .authorizeExchange(autorize -> autorize .pathMatchers(HttpMethod.OPTIONS, "/**").permitAll() .pathMatchers("/actuator/health/**").permitAll() .anyExchange().authenticated()) .oauth2ResourceServer(oauth2 -> oauth2.jwt(Customizer.withDefaults())); return http.build(); } Commented Dec 14, 2023 at 4:01
  • I think I have the same problem here: stackoverflow.com/questions/78802572/… Commented Jul 27, 2024 at 22:45

1 Answer 1

1

A simple way to avoid CORS errors without the need for CORS configuration is to have same origin (serve your website through the gateway too, not only the API).

gateway-uri: http://localhost:7080
ui-uri: http://localhost:4200
rest-api-service-uri: http://localhost:6080


spring:
  cloud:
    gateway:
      default-filters:
      - DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin
      routes:
      # Redirection from / to /ui/
      - id: home
        uri: ${gateway-uri}
        predicates:
        - Path=/
        filters:
        - RedirectTo=301,${gateway-uri}/ui/
      # Serve a SPA through the gateway (requires it to have a baseHref set as /ui)
      - id: ui
        uri: ${ui-uri}
        predicates:
        - Path=/ui/**
      # Access the API with BFF pattern
      - id: bff
        uri: ${rest-api-service-uri}
        predicates:
        - Path=/bff/v1/**
        filters:
        - TokenRelay=
        - SaveSession
        - StripPrefix=2

With

  • this routes definitions
  • gateway running on port 7080
  • REST API running on 6080
  • SPA hosted on let's say 4200

I can:

  • access the SPA assets from http://localhost:7080/ui/* (request are routed to http://localhost:4200/ui/*)
  • send REST requests to http://localhost:7080/bff/v1/* (request are routed to http://localhost:6080/*, the /bff/v1 prefix being stripped)

So with this setup, from the browser perspective, all network exchanges are made with http://localhost:7080 => no cross origin

P.S.

This is not the question, but configuring a gateway as a resource server is a bad idea, specially when it is queried by some Javascript code running in browsers.

It would better be configured as a client with oauth2Login() and the TokenRelay= filter. The REST APIs behind the gateway would then be candidates for oauth2ResourceServer() configuration. I posted a tutorial for that on Baeldung.

Sign up to request clarification or add additional context in comments.

5 Comments

I have set up where the gateway is set up as a resource server. I have some filters that will extract authentication details set some custom headers for the request and then pass them to the downstream services. I have my clients in angular and they act as OAuth clients. Do you think that this is a bad setup ?
Yes, I think that it is a bad setup. Spring Security team thinks too. I wrote this tutorial to meet Spring Security team (and many other experts) recommendations.
@ch4mp Thanks for the feedback. I am not much hands on this area but will keep your comments in my mind. I am working on a POC, not sure how folks want to setup the system at my work.
@Naim I have posted a tutorial for configuring SPAs (Angular, React or Vue) on Baeldung: baeldung.com/spring-cloud-gateway-bff-oauth2
I think I have the same problem here: stackoverflow.com/questions/78802572/…

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.