I am making requests with Angular2 app to a NodeJS API.
As long as I don't add custom headers, the calls are made and I got a response according to my request. But if I had a header by hand using interceptor
, it results in an error.
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at [api_url]. (Reason: CORS request did not succeed)
Here is the result of a login method, where I first call the server with no headers, and then add headers and call again the server.
The headers of the first POST method
And the one of the second POST method
The two custom headers are added by an interceptor in Angular as follow
...
const cloned = req.clone({
headers: req.headers.set("Authorization", "Bearer " idToken)
.set("X-QWEMP-data", encrypted)
});
req = cloned
...
And when I remove them, the route is reached but, of course, throw error because of the missing data.
Now, for my API, I have tried many configurations to allow custom headers. First was to add headers and return preflight OPTIONS manually as follow (not remember exactly how I did, but it's something like this)
app.use((req,res,next) => {
set.headers('Access-Control-Allow-Origin','*')
set.headers('Access-Control-Allow-Headers','Authorization,X-QWEMP-data')
if (req.method === 'OPTIONS') {
res.send()
return;
}else{
next()
return;
}
})
Then, I used cors
library and default configuration by just adding app.use(cors())
And finally, I have tried adding custom configuration in cors like follow (entire app.js
file)
require('dotenv').config()
const express = require('express');
const indexRouter = require('../routes/index');
const bodyParser = require('body-parser')
const cors = require('cors')
const morgan = require('morgan');
const app = express();
app.use(cors({
methods:'GET,POST,PUT,DELETE,OPTIONS',
allowedHeaders:'Authorization,X-QWEMP-data,Content-Type,[and all the already accepted headers in case]',
exposedHeaders:'[same as allowedHeaders]',
credentials:true,
preflightContinue:true
})
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
app.use(morgan('tiny'));
app.use('/', indexRouter)
app.listen(3000, () => {
console.log('Server listening on port 3000.')
})
EDIT
Screens of requests in network tab
First OPTION
First POST
Second OPTION
Second POST
CodePudding user response:
Adding a custom header causes the browser to require pre-flight for the cross origin request. This means the browser will send an OPTIONS request to your server for the same path and it must get back a 2xx response with the appropriate headers from that OPTIONS request or it will not send the actual follow-on request.
From what I can tell in the doc for the CORS module (and verified with a small experiment), when you set:
preflightContinue: true
You are telling the CORs middleware to skip that OPTIONS request and send it on to other request handlers. The doc specifically says: "Pass the CORS preflight response to the next handler". Since you have no other request handlers for that pre-flight request, your server will generate a 404 and the browser will see the pre-flight failed so your request will fail.
So, the first thing to try is to change to:
preflightContinue: false
If that still doesn't work, then please show the exact request as shown in the network tab of the Chrome debugger. It will show exactly what the browser is sending for pre-flight and will show exactly what your server is returning in response to that.
CodePudding user response:
The problem was not about CORS finally, even if it thrown an error.
In fact, the JWT was too long for not known reason. I used "Burp Suite" to intercept requests and added request in repeater to resend them and test with custom values.
So figuring this out, I needed to update the key used by jsonwebtoken
library to sign the JWT with a smaller one, and this way, the JWT was smaller.