Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. - node.js

I am using nodejs server, express framework and fetch library to send request to another server which is in different domain. For one of my endpoint consider (localhost:8080/login) i am rendering ejs file when the user clicks login button i am sending a fetch request to an api (https:otherserver.com/login) different server which is in other domain. i am not able to send this request. I am getting this error :
Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8080' is therefore not allowed access. The response had HTTP status code 404. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
I am not sure how to handle this issue. please suggest some ideas or links which can solve this issue.

You can use cors middleware on your server.
Simplest way to use it is to add :
app.use(cors())
before all of your route handlers.

I found the solution for my problem. I am trying to explain what i understood as i am a beginner in server side and web development.
This was the problem i faced :
For one of my endpoint in my nodejs server, consider (localhost:8080/login) i am rendering ejs file when the user clicks login button in that ejs file, i am sending a fetch request to an api (https:otherserver.com/signin) of different server which is in other domain. i am not able to send this request. I was getting cors problem.
Cors problem was occuring because the server domain(my nodejs server) which rendered the ejs file and the other domain(https:otherserver.com/signin) to which i was making fetch request after clicking login button was different.
so solution was :
I need to make the fetch request first to the same domain(my nodejs server localhost:8080/api/signin). And then from this server i should call the api of other domain(https:otherserver.com/signin). By doing this we wont get any cors issue. Because the client side ejs file is requesting to the same server which has rendered the file. And then the server is bypassing the request to the other server.
code from client side javascript file. /api/signin is an endpoint in my local nodejs server and u can add the options:
options ={
method : 'POST',
headers : {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
body : JSON.stringify({
email_address : emailId,
password : pwd
})
};
fetch("/api/signin",options)
.then(function(res) {
console.log(res);
}).catch(function(error) {
console.log(error);
});
code from local nodejs server side:
express.use('/api/', function (req, res, next) {
var options = {
method : req.method,
headers :req.headers,
body : JSON.stringify(req.body)
};
fetch('https://otherserver.com'+req.path,options)
.then(response => {
return response.json();
}, error => { console.error(error)})
.then(function(json){
res.send(json);
})
.catch(function(error) {
res.send(error);
});
})
Hope this may help someone who is beginner in server development.

Related

(Reason: CORS header ‘Access-Control-Allow-Origin’ missing). Status code: 204

I am trying to download a PDF from my backend. and i am getting this error.
Blockquote
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://192.168.1.115:5000/journal/download/HP-protein-prediction.pdf-1641052987115.pdf. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing). Status code: 204
Blockquote
I have enabled cors and tried a million things but it's not working.
Here's my code
Enabling Cors Code
Browser response
and finally my server side and frontend code
Server Side
Frontend request using Axios
My Logged Error :
Logging error Error: Network Error
createError createError.js:16
handleError xhr.js:117
dispatchXhrRequest xhr.js:114
xhrAdapter xhr.js:15
dispatchRequest dispatchRequest.js:58
request Axios.js:108
method Axios.js:129
wrap bind.js:9
downloadJournal apiCalls.js:64
onClick ViewArticle.js:23
React 14
unstable_runWithPriority scheduler.development.js:468
React 15
js index.js:9
js main.chunk.js:14047
Webpack 7
So as far as I can understand you are trying to download a pdf file in the frontend whenever you hit some API in the backend that sends the pdf to the frontend. I haven't tried the same with the Axios library but you can try using a normal fetch command
For Frontend
await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(body)
})
.then((response) =>
response.blob()
)
.then((blob) => {
console.log(blob)
// Create blob link to download
const url = window.URL.createObjectURL(
new Blob([blob]),
);
const link = document.createElement('a');
link.href = url;
link.setAttribute(
'download',
`${e.target.value}.pdf`,
);
// Append to html link element page
document.body.appendChild(link);
// Start download
link.click();
// Clean up and remove the link
link.parentNode.removeChild(link);
});
For Backend, I was using Nodejs which has a library file-system or fs
var file = await fs.readFileSync(`location-to-pdf/${req.body.fileId}.pdf`)
res.contentType("application/pdf");
res.send(file)
As of my experience if we use app.use(cors()) without specifying any configuration it works without any problem
The only doubt I had was about the URL of the API why is that not localhost whereas it's 192.168... if your app is running on localhost maybe you can send it directly to it without the rerouting
Major browsers its CORS policies prohibit this action, You CANNOT download any data from another domain/ip not the same of your frontend script domain/ip address.
Backend & Frontend must be exist in the same domain.
For development purpose, you can overcome this limitation by creating new shortcut with this target:
"[Path to Your Chrome]\chrome.exe" --disable-web-security --disable-gpu --user-data-dir=~/chromeTemp

HTTP request working from Postman and Node but not React

There are a few questions similar to this on Stack Overflow, and none of the proposed solutions worked, so I'll walk through the case and what I've tried.
I have a server application hosted on Cloud Run, which can only be accessed with the appropriate Bearer token in the request Authorization header. I've tried accessing it via Postman and an Axios request from a local Nodejs server, with the Authorization header, and it worked fine. With React (create-react-app specifically), I get the following error: Access to XMLHttpRequest at 'https://myserver-lhp5a9xp5a-ue.a.run.app/api/rules' 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.
On the server side, I get the 403 error that Cloud Run gives when the incorrect Authorization token is passed. Also, when I allow unauthenticated access from the Cloud Run side (so remove the need for an Authorization header), the request works fine, so it looks like this is indeed an issue with the Authorization header and not CORS.
In addition, I'm handling CORS on the server side. Here's my server-side code:
var express = require('express');
var router = express.Router();
const cors = require('cors');
router.options('/api/rules', cors());
router.get('/api/rules', cors(), (req, res, next) => {
res.status(200).send()
});
Here's my React code:
const axiosInstance = axios.create({
baseURL: process.env.REACT_APP_API_BASE_URL
});
const buttonClickHandler = async (event) => {
const resp = await axiosInstance.get('/api/rules'
, {
headers: {
'Authorization': 'Bearer eyJhbGciOiJSUzI1NiIsImtpZ...' // I used this token within the same minute when trying the request via Postman or from my Nodejs app, so a token expiry isn't the issue.
}
}
)
console.log(resp.data)
}
Here's what I tried so far:
Using fetch instead of axios - same error
Using the same token, within the same 5 seconds, to send the request from Postman or a Nodejs server - it worked fine.
Using an axios interceptor to set the Authorization - same error
Removing the single quotes around Authorization - same error
Sending the request to my Nodejs server instead and doing a console.log of the header to make sure the Authorization token is being passed correctly (it is)
Not using an an axios instance but spelling out the full URL in the request - same error
Trying a different endpoint on my Cloud Run server - same error
Deploying my React app to be served from a https endpoint and sending the request from there - same error
Adding Accept: '*/*' to the headers
Adding 'Accept': '*/*' to the headers
Adding 'Content-Type': 'application/json' to the headers
All combinations of the three above points
I found the answer after some digging, thanks #aniket-kolekar for pointing me in the right direction.
When Postman or a Nodejs server query an endpoint like GET, POST, PUT, DELETE, they send the call without checking the OPTIONS first. Create-React-App does.
The service I was querying is hosted on Cloud Run and doesn't allow unauthenticated invocations. So while I was including the authorization header to make my GET call, it wasn't being included in the pre-flight OPTIONS call. In fact, CORS prevents auth headers from being included in an OPTIONS call.
A Cloud Run PM replied in this post that this is a known issue with Cloud Run. The way I'll get around it for now is to host two services on Cloud Run - one that doesn't require authentication, and effectively acts as a proxy server to route calls from the client service to the shielded server service.
TLDR;
CORS is a mechanism built into the web browser. It’s not a UI code issue.
To fix CORS problems, you need to make changes on the API (server) side.
Here is the behind the scenes working:
Browser: Sends OPTIONS call to check the server type and getting the headers before sending any new request to the API endpoint. Where it checks for Access-Control-Allow-Origin. Taking this into account Access-Control-Allow-Origin header just specifies which all CROSS ORIGINS are allowed, although by default browser will only allow the same origin.
Postman: Sends direct GET, POST, PUT, DELETE etc. request without checking what type of server is and getting the header Access-Control-Allow-Origin by using OPTIONS call to the server.
You will have to configure Access-Control-Allow-Origin header in your server to resolve the CORS issue.

Is there anything I can do on the front end to read the response of a POST request to another domain?

I have a form
render() {
return (
<form onSubmit={this.handleSubmit}>
...
</form>
);
}
On submit I make a post request and print the response
handleSubmit(event) {
axios.post('https://.../oauth2/token', {
firstName: this.state.username,
password: this.state.password,
grant_type: password
})
.then(response => console.log(response))
event.preventDefault();
}
The printed response is
Failed to load https://.../oauth2/token: Response
to preflight request doesn't pass access control check: No
'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'http://localhost:3000' is therefore not allowed
access. The response had HTTP status code 400.
I understand that this is supposed to protect against cookie abuse. But is there anything I can do on the front end to get the response? Maybe I can state in the request that I don't want to use any cookie rights.
No 'Access-Control-Allow-Origin' header is present on the requested resource
Right there tells me what's wrong. You've got a problem with CORS (Cross-Origin Resource Sharing). If you're using Chrome, you can use an extension for it.
For a permanent solution, you'll have to enable CORS on your host server. I can't offer much help with that, as I've got no idea what your backend looks like. You can try searching for " CORS". Personally, I just use the extension when I'm developing for simplicity's sake, but I'm only working on an AngularJS mobile app.

"Fetch failed loading" - fetch works in Postman but fails in Chrome & Safari

Update: Fixed. It looks like the request was coming back as a 503 (as it should), then my app refreshed and displayed the non-error message: "Fetch failed loading". I just wasn't seeing the response because of the refresh.
I am not able to make a fetch request from my locally-hosted Create-React-App to my Heroku-hosted Node server.
My Node server has CORS enabled. If I make a POST request via Postman, I get an appropriate response (503, because currently there is no database hooked up, so the data is not being saved. If I should be sending back a different response, let me know). My Postman request has 'application/json' as the content-type, no authorization, and a body of { "rating": "5", "zipcode": "0" }.
However, when I make a POST request from my React app, I get a message in my console: "Fetch failed loading: OPTIONS "https://shielded-gorge-69158.herokuapp.com/feedback"." There is no associated error, only the message. There is no information about the request in my Network panel.
The fetch request works when I do it locally, from localhost:3000 (my app) to localhost:5000 (my server). It only fails when I try to make the request to the (otherwise identical) server hosted on Heroku.
This is what the fetch request looks like:
return fetch('https://shielded-gorge-69158.herokuapp.com/feedback', {
method: 'POST',
headers: {
'Content-type': 'application/json'
},
body: JSON.stringify({ rating: userRating, zipcode: userZip })
}).then(res => {
if (!res.ok) {
throw new Error('Error:', res.statusText);
}
return res;
}).catch(err => console.error(err));
Edit: I'm continuing to research and it seems like Postman shouldn't/doesn't make preflight requests (https://github.com/postmanlabs/postman-app-support/issues/2845). So perhaps that is the issue — but why would the request be working when my server is local, but not when it is hosted on Heroku?
use 'Content-Type' instead of 'Content-type'.
https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Simple_requests
https://fetch.spec.whatwg.org/#cors-safelisted-request-header
Explanation: when you use incorrect case then it is considered as a custom header and hence, a preflight request is sent in such cases. Now if OPTIONS request is implemented on server with correct cors spec then next POST will be sent, else it wont be sent and request will fail. More on this in above links.

Send Headers from NodeJS to Angular

I have a Node server running a single-page Angular web app. The requests to my server come in from a reverse proxy that attaches a set of headers for authentication. On certain events, the Angular app sends requests to another server, and those requests need to have the same authentication headerset that the Node server received from the reverse proxy. Is there a mechanism by which I can send the headers from Node to the client-side Javascript so that I can then pass them through in the requests made by my Angular web app?
You can use ExpressJS for NodeJs. There's a headers object present into request and response objects you can read/write. You can send it to client through a parameter (maybe) It depends what your client receive.
Example in coffee
# JSON response width previously req.headers
app.get /hello, (req, res) ->
res.json { status: 'OK', data: { headers: req.headers }
# Or you can use setHeader to set a special param in header
app.get /hello, (req, res) ->
res.setHeaders "foo", "bar"
res.json { status: 'OK' }
Hope this helps!

Resources