CORS blocking axios request with 'Authorization' Header and Data - node.js

Trying to send an axios post request from a Vue app (localhost) to my nodejs API (both localhost and heroku).
There are no issues receiving the response if the request is sent without data or headers, but as soon as I add them I get the following error:
Access to XMLHttpRequest at 'https://myapp.herokuapp.com/myendpoint' from origin 'http://localhost:8080'
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.
I have tried different options, both server and client side, as suggested on similar questions but had no success.
Client Request:
const apiUrl = 'https://myapp.herokuapp.com/myendpoint'
//const apiUrl = 'http://localhost:5000/myendpoint'
const token = Buffer.from(`${this.userid}:${this.password}`).toString('base64')
const data = {
'mydata': 'some data'
}
axios.post(apiUrl, data, {
headers: {
Authorization: "Basic " + token
}
}).then( res => {
console.log(res)
}).catch( err => {
console.log(err)
})
Server Endpoint:
app.post("/myendpoint", (req, res) => {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Methods", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
res.send('This is the API\'s response')
})
Some of the answers I tried:
Response to preflight request doesn't pass access control check
Nodejs Express CORS issue with 'Access-Control-Allow-Origin'
https://www.moesif.com/blog/technical/cors/Authoritative-Guide-to-CORS-Cross-Origin-Resource-Sharing-for-REST-APIs/
CORS authorization issue while using axios
How to send authorization header with axios

I think it is better if you define your cors using a global middleware. First off, install cors by using npm i cors.
Then, I'll show an example of how that package could be used.
const express = require('express');
const cors = require('cors');
const app = express();
app.use(cors());
// your routes and things here...
Then, ensure that your front-end also uses withCredentials set to true in the axios request. This is done to ensure that the header is being sent properly.
axios.post(apiUrl, data, {
headers: {
Authorization: "Basic " + token
},
withCredentials: true,
}).then(() => ...);
Sometimes, if you define Access-Control-* manually, you might forget something. That's why I recommend you to use cors.

Related

No CORS error when making GET requests, but CORS error when making POST requests

I have a Node/Express server that interacts with a React app.
I need to make POST and GET requests, the problem is that when making POST requests I get a CORS error, the usual:
Access to fetch at 'http://localhost:9000/testAPI' 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. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
I specified on the response on the server the Access-Control-Allow-Origin header, but I am not sure if I have to set this header for a POST request as well. And if I do, what domain should it specify?
I am also not willing to use hacks like CORS extensions, or npm packages. I want to use CORS.
The server-side looks like so:
const express = require("express");
const router = express.Router();
router.get("/", (req, res, next) => {
console.log(req.url);
res.setHeader("Access-Control-Allow-Origin", "http://localhost:3000");
res.send("API is working properly");
});
module.exports = router;
In the React app, the GET request looks like so (works just fine):
const res = await fetch('http://localhost:9000/testAPI');
console.log(res);
The POST request looks like so (CORS error thrown):
const res = await fetch('http://localhost:9000/testAPI', {
method: 'POST',
mode: 'cors',
cache: 'no-cache',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ someData: "POST requests are working properly" })
});
Do I need to specify some additional headers or properties on the POST request? Or do I have to modify something on the server-side?
If I will not have this problem when going live, than I do not mind using a hack like CORS extension.
You may use this package cors
// Install
npm install cors
yarn add cors
// server.js
const express = require('express');
const cors = require('cors');
const app = express();
// global middleware
app.use(cors());
// You can use route based middleware too
router.post("/", cors(), (req, res, next) => {
// process request & send response to client
});

http post request from Angular to Express server causes 404 error

I'm making a request to Azure function on local
url = 'http://localhost:7071/api/saveGraphDataFlow'
save(body) {
let headers = new HttpHeaders()
headers.append('Content-Type', 'application/json')
return this.httpClient.post(this.url, body, { headers: headers }).pipe(
map(res => {
return res
})
)
}
On my express server I'm adding cors to response
const createHandler = require("azure-function-express").createHandler;
const express = require("express");
const routers = require("./routes/routes");
const app = express();
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header(
"Access-Control-Allow-Headers",
"Origin, X-Requested-With, Content-Type, Accept"
);
res.header("Access-Control-Allow-Methods", "GET,PUT,POST,DELETE,OPTIONS");
next();
});
app.use("/api/", routers);
// Binds the express app to an Azure Function handler
module.exports = createHandler(app);
But when I send request I get this error :
Access to XMLHttpRequest at 'http://localhost:7071/api/saveGraphDataFlow' from origin 'http://localhost:4200' 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.
the preflight request is not passing
You could try to remove the extra slash from
app.use("/api/", routers);
and so it becomes:
app.use("/api", routers);
Also, as a sidenote, I have not seen your API router, and so maybe there is an extra slash or missing slash in there. Another thing I have noticed is that you're importing an entire folder (?) for your routers so make sure that you are importing a file at once. (i have not seen that, so this might not be true)

The "x-auth-token" header in Router.all() returns undefined

I am currently building an application using React for frontend and Nodejs for backend powered by Express.js.
I'm using jsonwebtoken for security method and applying a middleware called auth.js to authorize the request on every endpoints that starts with /rest, here is the code for auth.js:
const token = req.header('x-auth-token');
console.log(token); // Get the token from 'x-auth-token' header
if (!token) {
return res.status(400).json({ msg: 'Authorization denied. ' });
}
try {
// validate the token
next();
} catch (e) {
return res.status(401).json({ msg: 'Invalid token. '})
}
and the routing for /rest/* endpoints:
router.all("/", auth, (req, res) => {
// some codes
});
the request:
fetch(url + "/rest", {
method: "GET",
mode: "cors",
headers: {
"x-auth-token" : "this is the token" // define the header
"Accept" : "application/json",
"Content-Type" : "application/json",
}
});
The router.all() mechanism works fine, I'm able to access every /res routes with all methods. The problem is, the value of the x-auth-token header in the auth.js middleware always gives "undefined". when I change the routing to route.get() or route.post() etc.., that value of the x-auth-token returns the token from client correctly.
Am I missing something with the work around this router.all()? Thank you all.
EDIT: here's my cors middleware
module.exports = cors = (req, res, next) => {
res.setHeader('Access-Control-Allow-Origin', {domain});
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With, Content-Type , Accept, x-auth-token');
res.setHeader('Access-Control-Allow-Credentials', true);
next();
}
SOLVED:
So turns out, the reason why my x-auth-token header is missing in the req is because of the Pre-flight request mentioned by #Marcos Casagrande.
Now, what I went with is installing the CORS package and configured it following the Express documents and ended up with the following snippet in the server.js file since I want that cors configuration to be applied on every endpoints:
let cors = require("cors");
let whitelist = [{domains}]
let corsOptions = {
origin: (origin, callback) => {
if (whitelist.indexOf(origin) !== -1 || !origin) {
callback(null, true)
} else {
callback(new Error('Not allowed by CORS'))
}
}
}
app.use(cors(corsOptions));
Thank you all for helping me out.
When using router.all, OPTIONS will need to be handled, and x-auth-token won't be available there.
When you issue a request from the browser, an OPTIONS request will be issued first by the browser.
If you put:
console.log(req.method, req.headers);
You'll see: OPTIONS & x-auth-token missing. After OPTIONS has been handled correctly, the browser will issue the GET request, where the header will be present.
So you can handle it your self, and set the right Access-Control-Allow-Origin header if issuing a CORS request, or use cors package.
const app = require('express')();
const cors = require('cors');
app.use(cors());
// ...
router.all("/", auth, (req, res) => {
// No OPTIONS here, was already handled by `cors`
});
If you're not issuing a CORS request just use this in your auth middleware:
if(req.method === 'OPTIONS')
return res.send(); // 200
or handle options first
router.options('*', (req, res) => res.send());
router.all("/", auth, (req, res) => {
// some codes
});
Read more about Preflight Request
I see you are trying to access header value from req.header and not from req.headers, and you have a "Content-Type" : "application/json", in you GET request which will make a OPTION request anyway.
Your client app is making a cross origin request and you nodejs server must handle it. You can use the cors to solve this.
You can send token in any custom header, but a better practice/standardisation is to use Authorization header.

axios autohorization headers / CORS error

I'm using react with axios to fetch some information. I'm sending JWT token to auth user and im geting response in console browser
"Access to XMLHttpRequest at 'https://beer-tonight.herokuapp.com/beer/getBeerStatus' from origin 'http://localhost:3000' has been blocked by CORS policy: Request header field authorization is not allowed by Access-Control-Allow-Headers in preflight response."
This is my code:
componentWillMount(){
let token = localStorage.getItem('token');
axios.get('https://beer-tonight.herokuapp.com/beer/getBeerStatus', {headers: {Authorization : 'Bearer ' + token}}).then(
result => {
console.log('yey');
});
}
Error:
When I am using POSTMAN I am getting proper answer.
Postman input:
p.s. i already added :
app.use((req, res,next)=>{
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PATCH, DELETE');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorisation');
next();
You've written Authorisation:
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorisation');
But the header is Authorization as you have used with axios, try changing that and seeing if it works then,
I believe the cors error that you are receiving is from your node.js api. (https://beer-tonight.herokuapp.com/beer/getBeerStatus)
Since the host do are not the same origin (beer-tonight.herokuapp.com does not match with localhost), you need to enable cors for your node.js server.
If you are using express:
const express = require('express');
const cors = require('cors');
const app = express();
app.use(cors());
// ...
Source: here
Hapi.js:
server.connection({ routes: { cors: true } })
Source: here
Once you have CORS enabled, everything should work smoothly. More on CORS

Getting error "No 'Access-Control-Allow-Origin' header is present on the requested resource" after Heroku deployment [duplicate]

This question already has answers here:
Fetch API Post method is not working
(2 answers)
Angular2 application call node.js function
(1 answer)
Why does the browser send an OPTIONS request even though my frontend code is just making a POST request?
(2 answers)
Closed 4 years ago.
When I'm starting my server from localhost, it's not giving me any kind of error. But after deploying to Heroku, it's giving me the following cors error on some specific routes:
No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8080' is therefore not allowed access. The response had HTTP status code 503. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
I have tried almost everything to resolve this error and I have also tried all the possible solutions I found on stack overflow but nothing is working.
My code is simple: there is a login function which is sending a request to an API endpoint and that endpoint is ensuring whether the admin is authenticated or not.
My server code: ( using express js )
const expressApp = require('express');
const port = process.env.PORT || 3000;
const cors = require('cors');
const express = expressApp();
const bodyParser = require('body-parser');
const session = require('express-session');
const adminRoutes = require('./admin/admin-routes');
const userRoutes = require('./users/user-routes');
const bookingRoutes = require('./booking/booking-routes');
const contactRoutes = require('./contact-us/contact-routes');
require('./dbConnection.js');
express.use(function (req, res, next) {
console.log(req.headers);
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
res.header("Access-Control-Allow-Methods", "POST,DELETE,PUT,GET,OPTIONS");
res.header("Access-Control-Allow-Headers", req.headers['access-control-request-headers']);
res.header("Access-Control-Request-Method", req.headers['access-control-request-method']);
next();
});
The client side is :
fetch(url, {
method: "POST",
password: this.password,
body: JSON.stringify({
bodyData: { email }
}),
headers: {
'Access-Control-Allow-Origin': '*',
"Content-Type": "application/json"
}
}).then(res => {
return res.json()
}).then(user => {
// somthing here
}).catch(error => {
console.log(error);
})

Resources