Part of my Express configuration looks like this and runs on different domain
app.use(function(req, res, next) {
res.setHeader("Access-Control-Allow-Origin", 'http://localhost:3000');
res.setHeader("Access-Control-Allow-Credentials","true");
res.setHeader("Access-Control-Expose-Headers", "Set-Cookie");
res.setHeader("Access-Control-Allow-Headers", "Content-Type, x-xsrf-token, X-Requested-With, Accept, Expires, Last-Modified, Cache-Control");
res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS, DELETE");
next();
});
app.configure('development', 'production', function() {
app.use(express.csrf());
app.use(function(req, res, next) {
res.cookie('XSRF-TOKEN', req.csrfToken());
next();
});
});
When using CORS there is OPTIONS request before anything different than a GET. The server is manually configured to respond to it with 200 every time, so it proceed to the POST or whatever.
The requests come from Angular. Some said I need to add some of these lines in order to configure Angular properly.
$httpProvider.defaults.xsrfCookieName = 'XSRF-TOKEN';
$httpProvider.defaults.xsrfHeaderName = 'X-CSRFToken';
$httpProvider.defaults.useXDomain = true;
$httpProvider.defaults.withCredentials = true;
The error which I get is 403 Forbidden, the only solution so far is to comment out the whole app.configure(..) in the server. Obviously, I have some problem with CSRF and I cannot understand what should I do.
EDITED
This section of the doc says that
For requests without credentials, the server may specify "*" as a wildcard, thereby allowing any origin to access the resource.
Wildcard is used for completely public APIs which don't require an auth. If you want to use credentials (via cookies) you've got to set the exact list of allowed urls in Access-Control-Allow-Origin
Make sure res.setHeader("Access-Control-Allow-Credentials","true");
is used at the back end like:
app.use(function(req, res, next) {
res.setHeader("Access-Control-Allow-Origin", 'YOUR URL HERE');
res.setHeader("Access-Control-Allow-Credentials","true");
res.setHeader("Access-Control-Expose-Headers", "Set-Cookie");
res.setHeader("Access-Control-Allow-Headers", "Content-Type, x-xsrf-token, X-Requested-With, Accept, Expires, Last-Modified, Cache-Control");
res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
});
Also the $httpProvider.defaults.withCredentials = true;
should be used at the angular side to allow sending the credentials.
angular.module('CoolModule')
.config(['$httpProvider', function($httpProvider){
// For Access-Control-Allow-Origin and Set-Cookie header
$httpProvider.defaults.withCredentials = true;
}]);
or $http({withCredentials: true, ...}).get(...)
Hope this helps.
EDIT:
Not a solution, but as a workaround to allow the OPTIONS request this piece of code could be added:
...
res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
if ('OPTIONS' == req.method) {
res.send(200); } else { next();
}
...
You need to enable CORS support your angular.js app:
yourApp.config(['$httpProvider', function($httpProvider) {
$httpProvider.defaults.useXDomain = true;
delete $httpProvider.defaults.headers.common['X-Requested-With'];
}
]);
This should sort you out.
var allowCrossDomain = function(req, res, next) {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
res.header('Access-Control-Allow-Headers', 'Content-Type');
next();
}
app.use(allowCrossDomain);