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:
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:
I have also tried from a tiny ReactJS app and CORS are being block from there as well. Here is a screenshot:
Please help!
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
I can:
http://localhost:7080/ui/*
(request are routed to http://localhost:4200/ui/*
)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
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.