How to set Access-Control-Allow-Headers header in node-http-proxy - node.js

I am using the coinbase-pro library to make post request to the coinbase sandbox api through a form on localhost. I am trying to use node-http-proxy to get around a CORS error with no success. Ive been banging my head against the wall for a while on this, any help would be appreciated.
const express = require("express");
const httpProxy = require("http-proxy");
const port = 5050;
const app = express();
const proxy = httpProxy.createProxyServer({});
app.use(function(req, res) {
delete req.headers["origin"];
delete req.headers["referer"];
delete req.headers["host"];
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader(
"Access-Control-Allow-Headers",
"Content-type, cb-access-key,cb-access-passphrase,cb-access-sign,cb-access-timestamp"
);
res.setHeader(
"Access-Control-Allow-Methods",
"GET,POST,PUT,DELETE,OPTIONS"
);
const apiURL = 'https://api-public.sandbox.pro.coinbase.com'
proxy.web(req, res, { target: apiURL });
});
app.listen(port, () =>
console.log("Started proxy on port", port)
);
error:
Access to fetch at 'http://localhost:5050/orders' from origin 'http://localhost:3000' has been blocked by CORS policy: Request header field cb-access-passphrase is not allowed by Access-Control-Allow-Headers in preflight response.

The answer is here:
I think modifying the proxy response header is not covered in the current doc.
proxy.on('proxyRes', function(proxyRes, req, res) {
console.log('Raw [target] response', JSON.stringify(proxyRes.headers, true, 2));
proxyRes.headers['x-reverse-proxy'] = "custom-proxy";
proxyRes.headers['cache-control'] = "max-age=10000";
console.log('Updated [proxied] response', JSON.stringify(proxyRes.headers, true, 2));
// Do not use res.setHeader as they won't override headers that are already defined in proxyRes
// res.setHeader('cache-control', 'max-age=10000');
// res.setHeader('x-reverse-proxy', 'custom-proxy');
});
The key is to use proxyRes inside "proxyRes" event like proxyRes.headers[key] = value instead of relying on res.setHeader(key, value) as res.setHeader does not work when key is already exists among the proxy target response headers.

Related

CORS blocking axios request with 'Authorization' Header and Data

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.

CORS block in firebase cloud function

I'm implementing a cloud function to get results from BigQuery. My functions/index.js code below
const functions = require('firebase-functions');
const {BigQuery} = require('#google-cloud/bigquery');
const cors = require('cors')({origin: true});
exports.getBigQueryData = functions.region('europe-west3').https.onRequest((req,res) => {
cors(req,res,() => {
const bigquery = new BigQuery({
projectId: 'neon-opus-585',
keyFilename: 'service_account_bq.json'
});
const query = "SELECT * FROM `xxxx`";
bigquery.createQueryJob({query: query}).then((data) => {
const job = data[0];
return job.getQueryResults();
})
.then(results => {return res.send(results)})
.catch(error => {console.log(error)})
})
})
When i only deploy / test the function, everything runs OK, but when I use it from inside my application I get the following error
Access to fetch at 'https://xxxx.cloudfunctions.net/xxxx' from origin 'http://localhost:5000' 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.
As you can see I tried importing the cors package and implement it in my function as suggesting by several posts here but it is still not working.
Any help would be appreciated :)
Take a look into Handling CORS requests, there you have an example about this:
To handle a preflight request, you must set the appropriate Access-Control-Allow-* headers to match the requests you want to accept:
exports.corsEnabledFunction = (req, res) => {
// Set CORS headers for preflight requests
// Allows GETs from any origin with the Content-Type header
// and caches preflight response for 3600s
res.set('Access-Control-Allow-Origin', '*');
if (req.method === 'OPTIONS') {
// Send response to OPTIONS requests
res.set('Access-Control-Allow-Methods', 'GET');
res.set('Access-Control-Allow-Headers', 'Content-Type');
res.set('Access-Control-Max-Age', '3600');
res.status(204).send('');
} else {
res.send('Hello World!');
}
};
And Authentication with CORS:
If you plan to send a request with an Authorization header, you must:
Add the Authorization header to Access-Control-Allow-Headers.
Set the Access-Control-Allow-Credentials header to true.
Set a specific origin in Access-Control-Allow-Origin (wildcards are not accepted).
exports.corsEnabledFunctionAuth = (req, res) => {
// Set CORS headers for preflight requests
// Allows GETs from origin https://somedomain.com with Authorization header
res.set('Access-Control-Allow-Origin', 'https://somedomain.com');
res.set('Access-Control-Allow-Credentials', 'true');
if (req.method === 'OPTIONS') {
// Send response to OPTIONS requests
res.set('Access-Control-Allow-Methods', 'GET');
res.set('Access-Control-Allow-Headers', 'Authorization');
res.set('Access-Control-Max-Age', '3600');
res.status(204).send('');
} else {
res.send('Hello World!');
}
};

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.

Socket.io - Origin is not allowed access

I'm having this weird problem with socket.io. I have an express app which I run on port 5000. I have configured socket.io like this:
const app = require('../index');
const http = require('http');
const server = http.Server(app);
const io = require('socket.io')(server);
io.on('connection', function (socket) {
console.log('User has connected');
socket.emit('connect', {
message: 'Hello World'
});
});
Then I import this piece of code into my index.js file like this:
const express = require('express');
const app = module.exports = express();
const bodyParser = require('body-parser');
const cors = require('cors');
const request = require('request');
const boxRoutes = require('./routes/v1/boxRoutes');
const bidRoutes = require('./routes/v1/bidRoutes');
// use body parser so we can get info from POST and/or URL parameters
app.use(bodyParser.urlencoded({ limit: '10mb', extended: true }));
app.use(bodyParser.json({ limit: '10mb' }));
require('./services/usersClass');
// cors set up
app.use(cors());
app.use(function (req, res, next) {
console.log('Headers Middleware Called');
// Website you wish to allow to connect
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:3000');
// Request methods you wish to allow
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, DELETE');
// Request headers you wish to allow
res.setHeader('Access-Control-Allow-Headers', 'origin, x-requested-with, content-type, accept, x-xsrf-token', 'token');
// Set to true if you need the website to include cookies in the requests sent
// to the API (e.g. in case you use sessions)
res.setHeader('Access-Control-Allow-Credentials', true);
// Request headers you wish to expose
res.setHeader('Access-Control-Expose-Headers', false);
next();
});
// Middleware to authenticate the requests to this service
app.use(function(req, res, next) {
console.log('Auth Middleware Called');
if(!req || !req.headers['authorization']) return res.sendStatus(401);
const token = req.headers['authorization'].split(' ')[1];
request.post(
'http://localhost:4000/api/v1/users/auth',
{
headers: {
'Authorization': `Bearer ${token}`
}
},
function (error, response, body) {
if (!error && response.statusCode == 200) {
const data = JSON.parse(body);
res.locals.user = data.user;
next();
} else {
console.log('Request has failed. Please make sure you are logged in');
res.sendStatus(401);
}
}
);
});
app.use('/api/v1/boxes/', boxRoutes);
app.use('/api/v1/bids/', bidRoutes);
// disable 'powered by'
app.disable('x-powered-by');
app.listen(5000, () => {
console.log('Trading service is running on port 5000');
});
Now, in my client code, I try to establish socket.io connection when the user logs in. Everytime I try to connect to the server, I get the following error:
Failed to load
http://localhost:5000/socket.io/?EIO=3&transport=polling&t=MA_9wXE:
Response to preflight request doesn't pass access control check: The
value of the 'Access-Control-Allow-Origin' header in the response must
not be the wildcard '*' when the request's credentials mode is
'include'. Origin 'http://localhost:3000' is therefore not allowed
access. The credentials mode of requests initiated by the
XMLHttpRequest is controlled by the withCredentials attribute.
I don't understand why the connection fails. I have configured Access-Control-Allow-Origin to my client domain but it still fails.
You can use cors npm module. It will fix your problem.
var cors = require('cors')
var app = express()
app.use(cors({origin: '*'}))
start '*' means allow every origins. You can type spesific origin too.
I've seen this problem before, but never seen it manifested as a cross origin issue. You are creating two separate http servers. One you are making your express server and the other you are making your socket.io server. The code you show only actually starts the express server and you show no code that actually starts your socket.io server.
Here's where you create these two separate servers:
const server = http.Server(app); // creates the http server you use for socket.io
app.listen(5000, () => {...}); // creates the http server you use with Express
Inside of app.listen(), it creates it's own new server and starts it. Your other server is never started (at least per the code you show here).
When you probably want to do is to make your socket.io server use the same server as your express server and then you should be able to connect just fine without any CORs issues.
If you want to use app.listen(), it will return the server object that it created and you need to use that to initialize socket.io.
If you want to use the other server, then you need to share that with your express initialization code so it can use that one.

Resources