DELETE request's preflight fails on Firefox for Quarkus - reactjs

I'm getting a very strange error which I'm having a very hard time understanding why it's occurring.
Setup
I have a Quarkus backend which serves the following endpoints:
#Path("/rest/manager")
#ApplicationScoped
public class ManagerController {
...
#GET
#Path("/")
public Response getManagerList() {
...
}
#POST
#Path("/")
public Response createManager(#Valid ManagerView managerView) {
...
}
#GET
#Path("/{userId}")
public Response getManager(#Parameter(required = true) #PathParam("userId") String userId) {
...
}
#DELETE
#Path("/{userId}")
public Response deleteManager(#Parameter(required = true) #PathParam("userId") String userId) {
...
}
#PUT
#Path("/{userId}")
public Response updateManager(#PathParam("userId") String userId, #Valid ManagerView managerView) {
...
}
}
Quarkus application.properties looks like this:
quarkus.http.cors=true
quarkus.http.cors.origins=http://localhost:3000
quarkus.http.cors.methods=GET,POST,PUT,DELETE,OPTIONS
My frontend runs on localhost:3000 and backend on localhost:8080.
Frontend is in React, and i'm using axios to make the call like this:
.post<ManagerView>(`/manager`, managerToManagerView(data.manager), {
headers: {
Authorization: `Bearer ${data.accessToken}`,
'Content-Type': 'application/json',
},
})
...
.delete<boolean>(`/manager/${userId}`, {
headers: {
Authorization: `Bearer ${data.accessToken}`,
},
})
The Error
In Firefox, I get the following error when i make a Delete request.
XHR OPTIONS http://localhost:8080/rest/manager/auth0|63de17288141500bc6ac65e0
CORS Missing Allow Origin
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:8080/rest/manager/auth0|63de17288141500bc6ac65e0. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing). Status code: 400.
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:8080/rest/manager/auth0|63de17288141500bc6ac65e0. (Reason: CORS request did not succeed). Status code: (null).
Here's a screenshot from the Browser's devtools:
As you can see, just before the DELETE request, there is a POST request and the preflight for that is successful.
This is the details of the preflight which fails (the one before DELETE):
Also for comparison, here is the preflight request which doesn't fail (The one before POST)
This error only happens on DELETE or PUT. Other methods (POST and GET) are working fine.
This error only happens on Firefox, not on Chrome or Edge
Another interesting detail might be that on Chrome it doesn't work if I don't supply the Authorization header
I have tried various CORS settings for Quarkus however nothing works.

Related

Jeresy CORS filter working but React rest GET failing still with header ‘access-control-allow-origin’ is not allowed

I create a rest react front end to talk to a Jersey servlet on tomcat on the back end for RH 8.6. When react tried to do on REST GET or POST commands I got the "‘access-control-allow-origin’ is not allowed according to header" error. So I then added the CORS filter which was suppose to fix the origin problem, but the react client is still failing. I have tried different filters but there is no change. I assume the problem is in the react GET fetch but it looks ok with me and gets a header back when mode: 'no-cors' is set. In the debugger the CORSFilter class gets the GET, but it does not reach the resource class endpoint so its getting rejected.
Using postman I have verified the CORSFilter is inserting the values in the response as you can see here.
POST http://localhost:8080/rtc-servlet/mcd/location
Headers from postman tool:
Status Code: 200
access-control-allow-credentials: true
access-control-allow-headers: X-Requested-With, CSRF-Token, X-Requested-By, Authorization, Content-Type
access-control-allow-methods: API, GET, POST, PUT, DELETE, OPTIONS, HEAD
access-control-allow-origin: *
access-control-max-age: 151200
connection: keep-alive
content-length: 701
content-type: application/json
date: Sat, 10 Dec 2022 02:52:19 GMT
keep-alive: timeout=20
servlet code:
#Provider
public class CORSFilter implements ContainerResponseFilter {
#Override
public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext)
throws IOException {
// *(allow from all servers) OR https://crunchify.com/
responseContext.getHeaders().add("Access-Control-Allow-Origin", "*");
// As part of the response to a request, which HTTP headers can be used during the actual request.
responseContext.getHeaders().add("Access-Control-Allow-Headers",
"X-Requested-With, CSRF-Token, X-Requested-By, Authorization, Content-Type");
Also tried these options:
"Access-Control-Allow-Headers", "origin, content-type, accept, authorization");
responseContext.getHeaders().add("Access-Control-Allow-Credentials", "true");
responseContext.getHeaders().add("Access-Control-Allow-Methods",
"API, GET, POST, PUT, DELETE, OPTIONS, HEAD");
// How long the results of a request can be cached in a result cache.
responseContext.getHeaders().add("Access-Control-Max-Age", "151200");
}
}
#GET // read in updated/original files
#Produces(MediaType.APPLICATION_JSON) // what format we send back
public JsonObject getLocationValues() {
System.out.println("Called location getLocationValues ");
return locationRepository.readConfigFile(false);
}
React Rest GET fetch:
const urll1 = "http://localhost:8080/rtc-servlet/mcd/location";
useEffect(() => {
const fetchPost = async () => {
await fetch(urll1, {
// mode: 'no-cors',
headers: {
'Content-Type': 'application/json',
"Accept": "application/json",
"Access-Control-Allow-Origin": "*",
},
})
.then((response) => {
if (response.ok) {
response.json().then(data => {
console.log("response fetchPost :" + JSON.stringify(data));
setPosts1(data);
});
} else {
console.log("response was not ok");
}
})
.catch((err) => {
console.log(err.message);
});
};
fetchPost();
}, []);
The console error:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:8080/rtc-servlet/mcd/location. (Reason: header ‘access-control-allow-origin’ is not allowed according to header ‘Access-Control-Allow-Headers’ from CORS preflight response).
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:8080/rtc-servlet/mcd/location. (Reason: CORS request did not succeed). Status code: (null).
NetworkError when attempting to fetch resource.
So does anyone see that I am doing wrong?
After read the CORS not working posts in stackoverflow again I came across a commit about getting the origin from the header and then setting Access-Control-Allow-Origin to it vs. "*" and react on port localhost:3000 started to get responses back from the localhost:8080 servlet (origin is being set to "localhost:3000"). This was the forum string if you want to read up on it:
How to enable Cross domain requests on JAX-RS web services?.
So the change in the filter class is as follows:
String origin = requestContext.getHeaderString("origin");
if ((origin != null) && (!origin.isEmpty())) {
headers.add("Access-Control-Allow-Origin", origin);
} else {
// *(allow from all servers) OR https://crunchify.com/
headers.add("Access-Control-Allow-Origin", "*");
}
headers.add("Access-Control-Allow-Credentials", "true");
and in the js script "Access-Control-Allow-Origin": "*" was deleted:
await fetch(urll1, {
headers: {
'Content-Type': 'application/json',
"Accept": "application/json"
},
})
I am not sure if I now need the else since "*" didn't work for me, but I left it in. If its not needed or I am just doing something that sort of works because I am using firefox please let me know.

Getting CORS error rather than expected 429 response when rate limit is reached

In my backend I implemented an IpRateLimit middleware with the AspNetCoreRateLimit package in my .net core entity framework backend. When an IP Address x makes y calls in a specific time, it gets blocked for a certain time and the backend should return an 429 error and this works fine when testing with postman. But when the I make an request with axios, that is supposed to get blocked because of the ip rate limiter, I receive an axios error:
"Access to XMLHttpRequest at 'https://localhost:44372/api/Users/Login/' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource."
"POST https://localhost:44372/api/Users/Login/ net::ERR_FAILED"
After receiving this error, I have added the needed header, but it hasn't changed the result. Other axios requests to my backend (also post, put and delete) work fine, but when the ip rate limiter hits, I just get the cors error.
I implemented the limiter in my application as in the following tutorial:
https://edi.wang/post/2019/6/16/ip-rate-limit-for-aspnet-core
React axios request:
async function buildPostAndFetch(url, param, header) {
const finalurl = `${BASE_URL}${url}`;
return axios.post(finalurl, param, {headers:{"Access-Control-Allow-Origin": "*"}})
.then(res => {
response(res);
return res.data ? res.data : true;
})
.catch(err => {
handleError(err);
return false;
})
}
handleError() {
const handleError = err => {
setError(true);
if(err.request?.status === 0) {
console.log("*********************************************")
console.log(err.request);
console.log("*********************************************")
// throw new Error("API is currently offline or you are not connected to the internet:(");
} else if(err.response.status === 429) {
console.log("*********************************************")
console.log(err.response);
console.log("*********************************************")
}
}
}
When requestion and limiter hits I always get in the err.request.status === 0 path.
Most server systems/runtimes by default don’t add application-set headers to 4xx and 5xx responses but instead only add them to 2xx success responses and maybe to 3xx redirects.
So you may need to do explicit config to force headers to get added to 4xx responses, in order for that 429 response end up with the Access-Control-Allow-Origin header.
In Apache and nginx for example, that’s done by adding the always keyword to the header-setting directive. Maybe your server system has some similar thing.
You get a CORS error because that 429 error has no Access-Control-Allow-Origin header.
Firstly, ensure that you have Install-Package Microsoft.AspNetCore.Cors from NuGet.
Then, please add the following to your Startup.cs
public void ConfigureServices(IServiceCollection services)
{
// Put it before AddMvc() if there's any
services.AddCors();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
// Put it before UseMvc() if there's any
app.UseCors(
options => options
.WithOrigins("http://localhost:3000")
.AllowAnyHeader()
.AllowAnyMethod()
);
app.UseMvc();
}
After finish the above configuration, by inspecting on your network tab (Browser's developer tools) you may see the one of the returned response header is access-control-allow-origin : http://localhost:3000.
Try:
app.UseCors(opt => opt
.WithOrigins("http://localhost:3000"")
.AllowAnyHeader()
.AllowAnyMethod());
The protocol (http/https) can not be omitted. Also, the cors middleware should be placed after app.UseRouting but before UseAuthorization.
You can see Middleware Order .

React JS send post request to Springboot Rest Server and get error

I am hosting my React app in localhost:3000, and hosting my SpringBoot RESTServer at localhost:8080, tried to send a post request to that server and got following error:
Access to XMLHttpRequest at 'http://localhost:8080/employees' 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.
but i already put Access-Control-Allow-Origin in my code:
axios.post('http://localhost:8080/employees', params, {
headers: {
'Access-Control-Allow-Origin': '*',
'Content-Type': 'application/json',
'mode': 'no-cors'
}
}
)
API tested with postman and it worked.
Please help me.
That is caused by the CORS issue. You can google it and acquire lots of explanation which will tell you why the request is blocked when you call an api through the browser.
Basically, the CORS issue of Access-Control-Allow-Origin could be solved by setting you api endpoint. For sprint-boot api, you can try this two way.
Add #CrossOrigin onto the specific path controller
#CrossOrigin(origins = "http://localhost:3000")
#GetMapping("/employees")
public Employees getEmployees() {
// ...
}
Set the global CORS configuration
#Configuration
public class MyConfiguration {
#Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurerAdapter() {
#Override
public void addCorsMappings(CorsRegistry registry) {
// Allow all origin to call your api
registry.addMapping("/**");
}
};
}
}
You can reference this article for more clearly CORS settings in spring-boot.

Blocked by CORS policy "...does not have HTTP ok status" (Amplify and ReactJS, AWS Gateway and Lambda)

I'm almost embarassed to be asking this question due to CORS support out there on SO but I can't get by:
Access to XMLHttpRequest at 'https://a93xxxxx.execute-api.eu-west-1.amazonaws.com/dev[object%20Object]' from origin 'https://www.example.com' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: It does not have HTTP ok status.
I've even published my React project with Amplify and attempted it from the real domain name to even eliminate anything to do with the development environment (Cloud 9 running npm version 6.14.8)
I've also made a test running Chrome with the --disable-web-security flag.
My Lambda function contains the following (out of the box stub)
exports.handler = async (event) => {
// TODO implement
const response = {
statusCode: 200,
// Uncomment below to enable CORS requests
headers: {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Headers" : "Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With",
"Access-Control-Allow-Methods" : "OPTIONS,POST,GET,PUT"
}
,
body: JSON.stringify("Hello from Lambda!")
};
return response;
};
Note that I've uncommented the CORS request part and the response statusCode is set to 200.
The code in my application that execute when a submission form is sent from the client:
uploadcontactusdata = async data => {
try {
console.log("Contact Us pressed")
const settings = {
method: 'POST',
body: JSON.stringify(data),
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
}
}
const fetchResponse = await API.post('econtactus', settings);
Notification({
title: 'Success',
message: 'Notification has been sent',
type: 'success'
});
}
catch (err) {
console.log("unable to send");
console.error(err)
}
}
I created the API Gateway + Lambda using Amplify (version 4.41.2). Not sure where else to look now. Any clues will be appreciated. Thanks
You can completely get past the need for api gateway by using appsync.
amplify add api
Choose graphql (I have not tried using rest but you shouldn't need it) choose the basic schema, edit it if you'd like, and publish. Once it's published you can create your own method. You can view this inside the AppSync UI under Schema.
type Mutation {
yourMethod(input: Input!): TableName <-- add your method to the list
}
Now inside Appsync choose Data Sources and add datasource. Give it a name, choose lambda as the type, then find your lambda in the list. Once it's added go back to your schema and find the method you created above. On the right side bar locate your method and click the attach link. Find the data source you just added. Fill out the region and lambda ARN. MAKE SURE you choose new role and not an existing one.
You might need to configure the request and response templates.
For request:
{
"version" : "2017-02-28",
"operation": "Invoke",
"payload": $util.toJson($context.args)
}
For response:
$util.toJson($context.result)
Now you can call your lambda directly from the UI and return your result without worrying about CORS or managing API Gateway.

Enable CORS in springboot mail API

I have easy mail sending springboot API and reactjs app for fetch.
Hosted in nginx server.
React app running well localhost, email working everything okei but if I run on a server it gives an error.
I have tried to add different Nginx server settings and add Springboot
#CrossOrigin(origins = "http://xx.xxx.xxx.xxx/") but have not found any help so far.
Where do I have to allow CORS if I deploy to server?
Nginx server default:
server {
listen 80 default_server;
root /var/www/name/build;
server_name xx.xxx.xxx.xxx;
index index.html index.htm;
location / {
}
}
Springboot:
#PostMapping
public void sendFeedback(#RequestBody Feedback feedback,
BindingResult bindingResult){
if(bindingResult.hasErrors()){
throw new ValidationException("Feedback is not valid");
}
// Create a mail sender
JavaMailSenderImpl mailSender = new JavaMailSenderImpl();
Properties props = mailSender.getJavaMailProperties();
mailSender.setHost(this.emailCfg.getHost());
mailSender.setPort(this.emailCfg.getPort());
mailSender.setUsername(this.emailCfg.getUsername());
mailSender.setPassword(this.emailCfg.getPassword());
// Create an email instance
SimpleMailMessage mailMessage = new SimpleMailMessage();
mailMessage.setFrom(feedback.getEmail());
mailMessage.setTo("test#gmail.com");
mailMessage.setSubject("Testing mail");
mailMessage.setText(feedback.getFeedback());
mailSender.send(mailMessage);
}
Reactjs code I have:
fetch(url,{
method: 'POST',
headers:{
'Content-Type': 'application/json'
},
body: JSON.stringify(state)
}).then(response =>{
console.log(data)
}).catch(error =>{
console.log(error)
})
Output:
Access to fetch at 'http://xx.xxx.xxx.xxx:8080/feedback-0.0.1-SNAPSHOT' from
origin 'http://xx.xxx.xxx.xxx' has been blocked by CORS policy:
Response to preflight request doesn't pass access control check:
Redirect is not allowed for a preflight request.
Add a CORS config as below :
CORSConfig.java
#Configuration
public class CORSConfig implements WebMvcConfigurer {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("GET", "POST", "PUT", "DELETE", "HEAD");
}
}
OR
Annonate your controller
#CrossOrigin
#PostMapping
public void sendFeedback(#RequestBody Feedback feedback,
BindingResult bindingResult){
if(bindingResult.hasErrors()){
throw new ValidationException("Feedback is not valid");
}
// Create a mail sender
JavaMailSenderImpl mailSender = new JavaMailSenderImpl();
Properties props = mailSender.getJavaMailProperties();
mailSender.setHost(this.emailCfg.getHost());
mailSender.setPort(this.emailCfg.getPort());
mailSender.setUsername(this.emailCfg.getUsername());
mailSender.setPassword(this.emailCfg.getPassword());
// Create an email instance
SimpleMailMessage mailMessage = new SimpleMailMessage();
mailMessage.setFrom(feedback.getEmail());
mailMessage.setTo("test#gmail.com");
mailMessage.setSubject("Testing mail");
mailMessage.setText(feedback.getFeedback());
mailSender.send(mailMessage);
}
This is caused by your server not responding with the proper headers. If you look at your network tab you will see and OPTIONS request that fires before your POST request. Your server needs to respond to that OPTIONS request to let the browser know its ok for the requesting client to access the resource. You can read more about it here at MDN but at the very least your server should respond to the preflight with headers like:
Access-Control-Allow-Origin: http://foo.example <== your domain here
Access-Control-Allow-Methods: POST, OPTIONS
Access-Control-Allow-Headers: Content-Type
#CrossOrigin(origins="http://localhost:9000")
#GetMapping("/hello")
public Greeting greeting() {
return "world";
}
or
#CrossOrigin(origins="http://localhost:9000", maxAge=3600)
#RestController
public class RestController {}

Resources