I'm writing application that uses Angular for client side and NodeJs for backend.
I host my app with iis and iisnode.
Recently I added windows authentication to my application so I could know which user logged on.
Most of the requests works fine, but I got authorization problem with request that gets out of another route (/manage) but from the same origin.
My Angular code:
var url = "http://localhost:15001/auth/"+entredPass;
this.http.get(url, {withCredentials: true}).subscribe(res => {
...
});
My NodeJs code:
var app = express();
var allowCrossDomain = function (req, res, next){
res.header('Access-Control-Allow-Origin', origin); //Gets that from config
res.header('Access-Control-Allow-Credentials', true);
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
if(res.method == 'OPTIONS')
res.send(200);
else
next();
}
app.use(allowCrossDomain);
//This request works
app.get('isAlive', function(req, res){
res.setHeader('Access-Control-Allow-Origin', origin); //Gets that from config
res.status(200);
res.send(true);
});
//This one isn't - why?
app.get('/auth/:password', function (req, res){
...
var authRes = false;
if (password == "123456")
authRes = true;
res.setHeader('Access-Control-Allow-Origin', origin);
res.status(200);
res.send(authRes.toString());
});
For the second GET I get error:
No 'Access-Control-Allow-Origin' header is present on the requested
resouce. Origin 'http://myurl' is therefor not allowed access.
The only difference between this two requests is that the first one is called from 'http://myurl' and the second is called from 'http://myurl/manage'.
Although when I look at the network tab at the browser I see that the origin of the failed request is 'http://myurl'.
Why the 'Access-Control-Allow-Origin' is not presented and how can I solve it?
Thank you.
You can cors to do that.
CORS is a node.js package for providing a Connect/Express middleware that can be used to enable CORS with various options.
1 Install cors.
npm install cors
2 Then use it in your Express App.
const express = require('express');
const cors = require('cors');
const app = express();
app.use(cors());
//This request works
app.get('isAlive', function(req, res) {
res.setHeader('Access-Control-Allow-Origin', origin); //Gets that from config
res.status(200);
res.send(true);
});
//This one isn't - why?
app.get('/auth/:password', function(req, res) {
...
var authRes = false;
if (password == "123456")
authRes = true;
res.setHeader('Access-Control-Allow-Origin', origin);
res.status(200);
res.send(authRes.toString());
});
3 Optionally, you can also white-list specific domains if you want to:
const whitelist = ['http://example1.com', 'http://example2.com']
const corsOptions = {
origin: function (origin, callback) {
if (whitelist.indexOf(origin) !== -1) {
callback(null, true)
} else {
callback(new Error('Not allowed by CORS'))
}
}
}
app.use(cors(corsOptions));
Related
I'm trying to set up a basic user signup form with React, Node, and Express, and using fetch. However, I'm getting the following errors in the Chrome console when I try and send a post request:
1) "OPTIONS http://localhost:7001/v1/register 500 (Internal Server Error)"
2) "Access to fetch at 'http://localhost:7001/v1/register' from origin 'http://localhost:3001' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: It does not have HTTP ok status."
My eventual goal is to save the user's email and password in a database, but for now all I want is for the request to go through to the backend and have the backend log the body to make sure everything works. I've tried several different ways of setting headers, and I have no idea what's wrong. Below is the code.
Frontend form submit function:
handleSubmit(e) {
e.preventDefault();
const signUpInfo = this.state; // { email: 'test#gmail.com', password: '123' }
console.log(signUpInfo);
fetch('http://localhost:7001/v1/register', {
method: 'POST',
body: JSON.stringify(signUpInfo),
headers: {
'Content-Type': 'application/json'
}
})
.then(res => res.json())
.then(response => console.log('Success:', response))
.catch(error => console.error('Error:', error));
}
server.js
const express = require('express');
const compression = require('compression');
const cfg = require('config');
const path = require('path');
const logger = require('morgan');
const cookieParser = require('cookie-parser')
const bodyParser = require('body-parser');
const config = require('config');
const app = express();
app.use(compression());
app.use(bodyParser());
app.use(cookieParser());
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
app.use(express.static(path.join(__dirname, 'public')));
app.use(function(req, res, next) {
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader("Access-Control-Allow-Methods", "GET,POST,OPTIONS,DELETE");
res.setHeader("Access-Control-Allow-Headers", "X-Requested-With, Access-Control-Allow-Headers, Content-Type, Authorization, Origin, Accept");
res.setHeader('Access-Control-Allow-Credentials', true)
next();
});
// CONTROLLERS
const userController = require('./controllers/userController.js');
// ROUTES
app.post('/v1/register', userController.register);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
next(createError(404));
});
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
app.listen('7001', function() {
console.log('API server listening on port 7001!');
});
module.exports = app;
userController.js
exports.register = async (req, res, next) => {
try {
console.log(req.body);
res.status(200).json({ status: 200, data: req.body, message: "test" });
} catch (err) {
console.log(err);
res.status(500).json({ status: 500, data: null, message: err });
}
}
All I'm looking for is for the backend console to print out the body. It works with axios and $.ajax, but not with fetch. I've also tried using a proxy server to no avail (and would like to get it to work without a proxy).
Not sure if this is relevant, but I'm using Chrome as the browser and Sequelize.
Any help would be greatly appreciated. I feel like I'm missing something fundamental. Any helpful articles to deepen my learning would be a plus!
Instead of using
const app= express();
try to use
const app=express().use('*', cors());
and remove
app.use(function(req, res, next) {
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader("Access-Control-Allow-Methods", "GET,POST,OPTIONS,DELETE");
res.setHeader("Access-Control-Allow-Headers", "X-Requested-With, Access-Control-Allow-Headers, Content-Type, Authorization, Origin, Accept");
res.setHeader('Access-Control-Allow-Credentials', true)
next();
});
see if this works.
First Install "cors":
npm i cors
Second import "cors":
cors = reqquire("cors");
Third use "cors":
const app = express();
app.use("*", cors());
I have a REST Api, and all endpoints must send a response when the user has an authentication token (I use the jwt token).
everything works fine when I test my code using postman, but from front not working(session closes after OPTION request, and on the request header bearer token not set).
Authentication Middleware
module.exports = function(req, res, next) {
const authorization = req.headers['authorization'];
console.log(authorization);
const token = authorization
? authorization.replace('Bearer ', '')
: null;
if (!token)
return res.status(403).send({ auth: false, message: 'No token provided.' });
jwt.verify(token, config.secret, function(err, decoded) {
if (err)
return res.status(500).send({ auth: false, message: 'Failed to authenticate token.' });
req.userId = decoded.id;
next();
});
}
route
const Router = require('express').Router;
//Authentication Middleware
const requireAuthentication = require('../middlewares/').Auth()
module.exports = () => {
let router = new Router();
router.use(requireAuthentication);
router.use('/accounts', require('./account')());
router.use('/projects', require('./projects')());
return router;
};
with authentication
https://i.stack.imgur.com/cAFw5.png
without authentication
https://i.stack.imgur.com/VUuuv.png
The reason was in access headers
I add middleware in bootstrap file.
app.use(function(req, res, next) {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Methods', 'GET, PUT, POST, DELETE, OPTIONS');
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization, Content-Length, X-Requested-With');
if ('OPTIONS' === req.method) {
res.send(200);
}
else {
next();
}
});
Try to use Express Cors: https://github.com/expressjs/cors
Simple Usage (Enable All CORS Requests)
var express = require('express')
var cors = require('cors')
var app = express()
app.use(cors())
app.get('/products/:id', function (req, res, next) {
res.json({msg: 'This is CORS-enabled for all origins!'})
})
app.listen(80, function () {
console.log('CORS-enabled web server listening on port 80')
})
Cross-Origin Resource Sharing (CORS) is a mechanism that uses additional HTTP headers to tell a browser to let a web application running at one origin (domain) have permission to access selected resources from a server at a different origin. A web application makes a cross-origin HTTP request when it requests a resource that has a different origin (domain, protocol, and port) than its own origin.
Read more about CORS here https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
I tried about 10 different options but I cant get my POST request start working instead i have options request that is pending and never completes
server.js
var express = require('express');
var path = require('path');
var mongoose = require('mongoose');
var bodyParser = require('body-parser');
var cors = require('cors');
var app = express();
app.use(cors());
var allowCrossDomain = function(req, res, next) {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization, Content-Length, X-Requested-With, Accept');
// intercept OPTIONS method
if ('OPTIONS' == req.method) {
res.send(200);
} else {
next();
}
};
app.use(allowCrossDomain);
app.options('*', cors());
app.use(require('./routes/order-templates.js'));
app.use(require('./routes/statuses.js'));
app.use(require('./routes/fields.js'));
app.use(require('./routes/users.js'));
app.use(require('./routes/groups.js'));
app.use(require('./routes/upload.js'));
app.use(require('./routes/feedback.js'));
app.use(require('./routes/order.js'));
app.use(express.static('public'));
var mongoDB = 'mongodb://localhost/ior';
mongoose.connect(mongoDB, {
useMongoClient: true
});
app.get('*', function (request, response) {
response.sendFile(path.resolve(__dirname, 'public', 'index.html'))
})
app.listen(3000, function () {
console.log('Fired at ' + Date());
});
users.js
var express = require('express');
var router = express.Router();
var User = require('../model/user.js');
var bodyParser = require('body-parser');
var app = express();
var cors = require('cors')
var corsOptions = {
origin: 'http://188.225.82.166:3000/',
optionsSuccessStatus: 200
}
app.use(cors())
app.use(bodyParser.json());
app.options('/users/auth/', cors(corsOptions))
app.post('/users/auth/', cors(), function (req, res, next) {
User.findOne({"mail": req.body.mail, "password": req.body.password}, function (err, user) {
if (err) throw err;
if (user == undefined) {
res.send({"result": "error" })
res.sendStatus(200)
} else {
res.send({"result": "ok", "_id": user._id, "type": user.type })
}
});
})
module.exports = app
If I do
app.use(cors());
app.use(function(req, res, next) {
console.log('After CORS ' + req.method + ' ' + req.url);
next();
});
in server.js I get
After CORS GET /
After CORS GET /bundle.js
After CORS GET /bootstrap.css.map
After CORS GET /favicon.ico
And nothing prints in console after post requests is triggered.
Also worth mentioning the fact, that the problem exists only when I deploy to server with ubuntu. Locally on mac os machine everything is fine
You should use cors before bodyParser and allow it for PUT/DELETE also.
// Add cors
app.use(cors());
app.options('*', cors()); // enable pre-flight
app.use(bodyParser.json());
It may be helpful for others like me:
In the beginning I thougth it is the server side problem, but then the reason of cors error became my frontend. I was sending requests to localhost:3000/api instead of http://localhost:3000/api
That's it
For others like me scratching head for 2hrs trying to fix the POST cors issue, please also double check the options of your POST request.
For me it was a small typo of header: {...} instead of header(s): {...} in the POST options, the express server configured using cors allowing all origins responded with "Access-Control-Allow-Origin" restricted error.
Try this. In you user.js file use router.post instead of app.post.
router.post('/users/auth/', cors(), function (req, res, next) {
User.findOne({"mail": req.body.mail, "password": req.body.password}, function (err, user) {
if (err) throw err;
if (user == undefined) {
res.send({"result": "error" })
res.sendStatus(200)
} else {
res.send({"result": "ok", "_id": user._id, "type": user.type })
}
});
})
Then export router module
module.exports = router;
Also i would suggest to use bodyparser in server.js file. So you don't need to use it in every file.
After applying "cors" middleware. You should append "http://" before "localhost:". in URL
axios.get("http://localhost:8080/api/getData")
.then(function (response) {
this.items= response.data;
}).catch(function (error) {
console.log(error)
});
Get rid of the trailing slash in origin.
I've already configured cors in my nodejs application as follow:
cors = require('cors');
var whitelist = ['http://first.url', 'https://test.cloudfront.net']
var corsOptions = {
origin: function (origin, callback) {
if (whitelist.indexOf(origin) !== -1) {
callback(null, true)
} else {
callback(new Error('Not allowed by CORS'))
}
}
}
router.get('/home', cors(corsOptions), controller.index);
It's working and fetch data from nodejs app from http://first.url but when I tested with https://test.cloudfront.net, it's not working and return following error.
XMLHttpRequest cannot load https://server.cloudfront.net/api/app/home.
No 'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'https://test.cloudfront.net' is therefore not
allowed access.
Please let me know how come that error is return. Because of some configuration is missing in cloudfront?
Browser send before an OPTIONS request to the server to know if it accept cross origin request, just handle OPTIONS request with a simple middleware
app.use(function(req,res, next){
if(req.method == "OPTIONS"){
res.header('Access-Control-Allow-Headers', "*");
res.header('Access-Control-Allow-Methods', "POST, GET, OPTIONS, PUT, PATCH, DELETE");
res.header('Access-Control-Allow-Origin', "*");
res.header('Access-Control-Allow-Credentials', true);
return res.sendStatus(200);
}
else
return next();
});
I have a REST api created with the restify module and I want to allow cross-origin resource sharing. What is the best way to do it?
You have to set the server up to set cross origin headers. Not sure if there is a built in use function or not, so I wrote my own.
server.use(
function crossOrigin(req,res,next){
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "X-Requested-With");
return next();
}
);
I found this from this tutorial. http://backbonetutorials.com/nodejs-restify-mongodb-mongoose/
The latest version of Restify provides a plugin to handle CORS.
So you can now use it like this:
server.use(restify.CORS({
// Defaults to ['*'].
origins: ['https://foo.com', 'http://bar.com', 'http://baz.com:8081'],
// Defaults to false.
credentials: true,
// Sets expose-headers.
headers: ['x-foo']
}));
This works for me:
var restify = require('restify');
var server = restify.createServer();
server.use(restify.CORS());
server.opts(/.*/, function (req,res,next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Methods", req.header("Access-Control-Request-Method"));
res.header("Access-Control-Allow-Headers", req.header("Access-Control-Request-Headers"));
res.send(200);
return next();
});
server.get('/test', function (req,res,next) {
res.send({
status: "ok"
});
return next();
});
server.listen(3000, function () {
console.log('%s listening at %s', server.name, server.url);
});
This is what worked for me:
function unknownMethodHandler(req, res) {
if (req.method.toLowerCase() === 'options') {
console.log('received an options method request');
var allowHeaders = ['Accept', 'Accept-Version', 'Content-Type', 'Api-Version', 'Origin', 'X-Requested-With']; // added Origin & X-Requested-With
if (res.methods.indexOf('OPTIONS') === -1) res.methods.push('OPTIONS');
res.header('Access-Control-Allow-Credentials', true);
res.header('Access-Control-Allow-Headers', allowHeaders.join(', '));
res.header('Access-Control-Allow-Methods', res.methods.join(', '));
res.header('Access-Control-Allow-Origin', req.headers.origin);
return res.send(204);
}
else
return res.send(new restify.MethodNotAllowedError());
}
server.on('MethodNotAllowed', unknownMethodHandler);
I this code was taken from https://github.com/mcavage/node-restify/issues/284
CORS Plugin is deprecated in favor of https://github.com/Tabcorp/restify-cors-middleware. (Source: https://github.com/restify/node-restify/issues/1091.)
Below is a sample code regarding how to use
const corsMiddleware = require('restify-cors-middleware')
const cors = corsMiddleware({
preflightMaxAge: 5, //Optional
origins: ['http://api.myapp.com', 'http://web.myapp.com'],
allowHeaders: ['API-Token'],
exposeHeaders: ['API-Token-Expiry']
})
server.pre(cors.preflight)
server.use(cors.actual)
If anyone comes across this as of Feb 2018 there seems to be a bug that's been introduced, I couldn't get the restify-cors-middleware to work.
I'm using this work around for now:
server.pre((req, res, next) => {
res.header("Access-Control-Allow-Origin", "*");
next();
});
To enable CORS for basic authentication I did the following. It did not work until the .pre methods were used instead of the .use methods
server.pre(restify.CORS({
origins: ['https://www.allowedip.com'], // defaults to ['*']
credentials: true,
headers: ['X-Requested-With', 'Authorization']
}));
server.pre(restify.fullResponse());
function unknownMethodHandler(req, res) {
if (req.method.toLowerCase() === 'options') {
var allowHeaders = ['Accept', 'Accept-Version', 'Content-Type', 'Api-Version', 'Origin', 'X-Requested-With', 'Authorization']; // added Origin & X-Requested-With & **Authorization**
if (res.methods.indexOf('OPTIONS') === -1) res.methods.push('OPTIONS');
res.header('Access-Control-Allow-Credentials', true);
res.header('Access-Control-Allow-Headers', allowHeaders.join(', '));
res.header('Access-Control-Allow-Methods', res.methods.join(', '));
res.header('Access-Control-Allow-Origin', req.headers.origin);
return res.send(200);
} else {
return res.send(new restify.MethodNotAllowedError());
}
}
server.on('MethodNotAllowed', unknownMethodHandler);
I do it like this on my restify base app:
//setup cors
restify.CORS.ALLOW_HEADERS.push('accept');
restify.CORS.ALLOW_HEADERS.push('sid');
restify.CORS.ALLOW_HEADERS.push('lang');
restify.CORS.ALLOW_HEADERS.push('origin');
restify.CORS.ALLOW_HEADERS.push('withcredentials');
restify.CORS.ALLOW_HEADERS.push('x-requested-with');
server.use(restify.CORS());
you need to use restify.CORS.ALLOW_HEADERS.push method to push the header u want into restify first, then using the CORS middleware to boot the CORS function.
MOST OF THE PREVIOUS ANSWERS ARE FROM 2013 AND USE DEPRECATED EXAMPLES!
The solution (in 2017 at least) is as follows:
npm install restify-cors-middleware
Then in your server javascript file:
var corsMiddleware = require('restify-cors-middleware');
var cors = corsMiddleware({
preflightMaxAge: 5,
origins: ['*']
});
var server = restify.createServer();
server.pre(cors.preflight);
server.use(cors.actual);
And add whatever additional other options work for you. My use case was creating a localhost proxy to get around browser CORS issues during devolopment. FYI I am using restify as my server, but then my POST from the server (and to the server) is with Axios. My preference there.
npm listing for restify-cors-middleware
This sufficed in my case:
var server = restify.createServer();
server.use(restify.fullResponse());
server.get('/foo', respond(req, res, next) {
res.send('bar');
next();
});
It wasn't necessary to server.use(restify.CORS());
Also, it appears server.use() calls must precede server.get() calls in order to work.
This worked for me with restify 7
server.pre((req, res, next) => {
res.header('Access-Control-Allow-Origin', req.header('origin'));
res.header('Access-Control-Allow-Headers', req.header('Access-Control-Request-Headers'));
res.header('Access-Control-Allow-Credentials', 'true');
// other headers go here..
if(req.method === 'OPTIONS') // if is preflight(OPTIONS) then response status 204(NO CONTENT)
return res.send(204);
next();
});
I am using Restify 7.2.3 version and this code worked for me very well.
You need to install the restify-cors-middleware plugin.
const corsMiddleware = require('restify-cors-middleware')
const cors = corsMiddleware({
preflightMaxAge: 5, //Optional
origins: ['http://ronnie.botsnbytes.com', 'http://web.myapp.com'],
allowHeaders: ['API-Token'],
exposeHeaders: ['API-Token-Expiry']
})
server.pre(cors.preflight)
server.use(cors.actual)
const cors = require('cors');
const server = restify.createServer();
server.use(cors());
This worked for me
const restify = require('restify');
const corsMiddleware = require('restify-cors-middleware');
const cors = corsMiddleware({
origins: ['*']
});
const server = restify.createServer();
server.pre(cors.preflight);
server.use(cors.actual);
server.get('/api/products', (request, response) => {
response.json({ message: 'hello REST API' });
});
server.listen(3000, () => console.info(`port 3000`));
... is one brute-force solution, though you should be very careful doing that.