MEAN stack error Authorization error: no "Access-Control-Allow-Origin" header?
I am trying to do facebook authorization in my MEAN stack application. I am using passport
and passport-facebook
. I am not using jade
or ejs
, I want to use pure angular. When I launch my application and click the Login button, I get the following error:
XMLHttpRequest cannot load https://www.facebook.com/dialog/oauth?response_type=code&redirect_uri=http%…2Flocalhost%3A3030%2Fauth%2Ffacebook%2Fcallback&client_id=....
No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3030' is therefore not allowed access.
I did some research and found that the node module cors
can fix this, but it doesn't.
What did I do wrong and how can I fix it?
Here is my routes.js file (server side):
app.get('/auth/facebook', passport.authenticate('facebook'));
app.get('/auth/facebook/callback', passport.authenticate('facebook', {
successRedirect: '/success',
failureRedirect: '/error'
}));
app.post('/success', function(req, res, next) {
User.findById(req.session.passport.user, function(err, user) {
if(err){
res.send({success:false});
}else{
res.send({success:true,user: user});
}
});
});
app.get('/logout', function(req, res){
req.logout();
res.redirect('/');
res.end();
});
app.post('/error', function(req, res, next) {
res.send({success:false});
});
Here is my file passport.js
(server side):
Note. clientID
, clientSectret
and callbackURL
are in another file ( config.js
). But they are valid.
passport.use(new FacebookStrategy({
clientID: config.facebookAuth.clientID,
clientSecret: config.facebookAuth.clientSecret,
callbackURL: config.facebookAuth.callbackURL
},
function(accessToken, refreshToken, profile, done) {
User.findOne({ oauthID: profile.id }, function(err, user) {
if(err) { console.log(err); }
if (!err && user != null) {
done(null, user);
} else {
var user = new User({
oauthID: profile.id,
name: profile.displayName,
created: Date.now()
});
user.save(function(err) {
if(err) {
console.log(err);
} else {
console.log("saving user ...");
done(null, user);
}
});
}
});
}
));
// serialize and deserialize
passport.serializeUser(function(user, done) {
console.log('serializeUser: ' + user._id)
done(null, user._id);
});
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user){
console.log(user)
if(!err) {done(null, user);}
else {done(err, null)}
});
});
And here is my express config file: express.js
(server side):
var express = require('express'),
passport = require('passport'),
cookieParser = require('cookie-parser'),
bodyParser = require('body-parser'),
session = require('express-session'),
cors = require('cors');
var whitelist = ['https://www.facebook.com'];
var corsOptions = {
origin: function(origin, callback){
var originIsWhitelisted = whitelist.indexOf(origin) !== -1;
callback(null, originIsWhitelisted);
}
};
module.exports = function (app, config) {
app.set('view engine', 'ejs');
app.use(cookieParser());
app.use(bodyParser());
app.use(cors(corsOptions));
app.use(session({secret:"car advisor secret"}));
app.use(passport.initialize());
app.use(passport.session());
app.use(express.static(config.rootPath+"/public"));
}
CLIENT SIDE
Here is my html file:
<body>
<div class="navbar-right" ng-controller="LoginCtrl">
<form class="navbar-form" >
<a class="btn btn-primary" ng-click="signin()" ng-show="!identity.isAuthenticated()">Sign in</a>
<a class="btn btn-primary" ng-click="signout()" ng-show="identity.isAuthenticated()">Sign out | {{identity.currentUser.name}}</a>
</form>
</div>
<ng-view></ng-view>
Here is my login controller:
$scope.signin = function(username, password) {
authService.authenticateUser(username, password).then(function(success) {
if (success){
console.log("You have successfully signed in!");
}
});
}
$scope.signout = function() {
authService.logoutUser().then(function() {
console.log("You have successfully signed out!");
$location.path('/');
});
}
And here is my service that handles communication with the server (authService.js):
carApp.factory('authService', function($http, Identity, $q, $cookieStore, $resource) {
return {
authenticateUser: function(username, password) {
var dfd = $q.defer();
$http.get('/auth/facebook').
success(function(data, status, headers, config) {
if (data.success) {
Identity.currentUser = response.data.user;
$cookieStore.put('user', response.data.user);
dfd.resolve(true);
} else {
$cookieStore.remove('user');
dfd.resolve(false);
}
});
return dfd.promise;
},
logoutUser: function() {
var dfd = $q.defer();
$http.get('/logout').success(function() {
Identity.currentUser = undefined;
$cookieStore.remove('user');
dfd.resolve();
});
return dfd.promise;
}
source to share
You cannot make ajax request to another address. Even if the address is the same and the port is different, you will have problems with the same initial policy.
You can do this with nginx and redirect the request with proxy_pass
.
something like
server
{
listen 80;
server_name localhost;
location /auth/facebook/request {
proxy_pass http://(...)facebook.com/(...);
}
}
source to share
I'm not sure if this solves your problem, but I recently went through something similar while trying to make facebook login to angular app. make sure on facebook app settings page,
https://developers.facebook.com/apps/{your_app_id}/settings/
change the "site url" to whatever your local site is. For example:
http://localhost:8080/
source to share
Hi I'm not sure if this help will help you.
app.config(['$httpProvider', function ($httpProvider){
$httpProvider.defaults.useXDomain = true;
// $httpProvider.defaults.cache = true;
$httpProvider.defaults.withCredentials = true;
// $httpProvider.defaults.xsrfCookieName = '';
// $httpProvider.defaults.xsrfHeaderName = '';
delete $httpProvider.defaults.headers.common['X-Requested-With'];
}]);
source to share