I'm working with nodejs+express+mongo and angularjs(MEAN). I'm login in with Facebook strategy for passport but I can't seem to find the way to access the user info(req.user) from my angular client.
It should be noted that the angular front is on another app and web server, apart from the node express mongo side.
This is my nodejs code:
passport.serializeUser(function(user, done){
done(null, user._id);
});
passport.deserializeUser(function(id, done){
UserModel.findById(id, function(err, user){
done(err, user);
});
});
passport.use(new FacebookStrategy({
clientID: config.facebook.appId,
clientSecret: config.facebook.appSecret,
callbackURL: config.facebook.redirectUri,
scope: config.facebook.scope,
profileFields: ['name','displayName','gender','profileUrl','email']
},
function(accessToken, refreshToken, profile, done) {
UserModel.findOne( {$or:[{'facebook_profile.id': profile.id},{'email':profile.emails[0].value}]}, function(err, user){
var newuser = new UserModel();
if(err){
return done(err);
}
if(user){
return done(null, user);
}
else {
newuser.facebook_profile.id = profile.id;
newuser.facebook_profile.name = profile.displayName
return done(null, newuser);
}
});
})
);
app.get('/auth/is_auth', function(req, res){
if (req.isAuthenticated()){
res.json(req.user);
}
})
After this, from Postman I call
http://localhost:3000/auth/is_auth
But req.isAuthenticated() is always FALSE
What can it be, I can't never get the user info
req.isAuthenticated() is false, if you use CORS and in your ajax request you didn't set withCredentials to true. Be sure withCredentials is set to true.
Related
I'm using passport-linkedin to integrate LinkedIn account in my project. Problem is when linkedin email does not found in my database, I need to display linkedin account information in callback function.
passport.js
passport.use(new LinkedInStrategy({
consumerKey: '12121',
consumerSecret: '1212121',
callbackURL: "/auth/linkedin/callback",
profileFields: ['id', 'first-name', 'last-name', 'email-address', 'headline']
},
function(token, tokenSecret, profile, done) {
auth.findOne({ username: profile.emails[0].value }).then(function (err, user) {
if (!user) {
return done(null, profile);
} else {
return done(null, user);
}
}, function (err) {
return done(err, null);
})
}
));
routes.js
app.get('/auth/linkedin/callback',
passport.authenticate('linkedin', { failureRedirect: '/login' }),
function(req, res) {
winston.error('linkedInfo: %s', req);
res.redirect('/');
});
In routes.js, I want to display all of json data from LinkedIn. But nothing display as not working at all.
One thing to check would be ensuring that you are requesting the r_basicprofile and r_emailaddress member permissions during the OAuth process, if you want to return a member's email address.
The entire call could be failing (and obscured to you via the Passport layer) as a result of you not having the necessary permissions to request all of the fields you are asking for.
I saw this very nice article from Scotch.io:
https://scotch.io/tutorials/easy-node-authentication-linking-all-accounts-together
It is from January 2014, so it's getting a bit old :) but Chris shows us how we might check the value of req.user inside the passport.authenticate('linkedin') callback, like so:
passport.use(new LinkedInStrategy({
consumerKey: linkedinConfig.clientId,
consumerSecret: linkedinConfig.clientSecret,
callbackURL: serverBaseUrl + '/auth/linkedin/callback'
},
function (req, token, tokenSecret, profile, done) {
if (req.user) {
var user = req.user;
user.linkedin.id = profile.id;
user.linkedin.token = token;
user.save(function (err) {
if (err) {
done(err);
}
else {
done(null, user);
}
});
}
else{
User.findOne({'linkedin.id': profile.id}, function (err, user) {
if (err) {
done(err);
}
else if (user) {
done(null, user);
}
else {
done(null, null);
}
});
}
}
));
my question is - how did Chris get the req value passed to this callback?
in other words the callback signature is supposed to be this:
function (token, tokenSecret, profile, done)
not this
function (req, token, tokenSecret, profile, done)
...now passport appears to be standard Express middleware, with the signature of
module.exports = function(req,res,next){};
but I don't see how to access the req variable with Passport the way Chris does. Am I missing something from his article somehow?
Looking at tutorial , try this :
passport.use(new LinkedInStrategy({
consumerKey: linkedinConfig.clientId,
consumerSecret: linkedinConfig.clientSecret,
callbackURL: serverBaseUrl + '/auth/linkedin/callback',
passReqToCallback : true
}
LinkedIn strategy inherits from Oauth1 strategy in this line explains how works , this should be sufficient. hope it helps.
I am trying to make a node.js web application that tells the user to sign in using their gmail.
So I tried to use the instructions over here: http://passportjs.org/guide/google/. I changed the url www.example.com to localhost, then ran the application. It tells me that it can't find User. Here is the whole log: User.findOrCreate({openID: identifier }, function(err, user) {(and then on the next line) ReferenceError: User is not defined.
You need to define "User" by calling it from a model. Create a User model (if you haven't already) and import it as a variable. E.g.
var User = require('/path/to/User');
Sometimes I find it helpful for debugging to log the callback to the console, to see if the desired output is being spit out.
I just implemented one maybe this will help , I'm using Express the routes section is on the bottom.. Remember to set your host in the Google Key, my App has de full url of the AWS Server
var passport = require('passport');
// ====== Passport and OAuth2 API
var GoogleStretegy = require('passport-google-oauth').OAuth2Strategy;
passport.serializeUser(function (user, done) {
done(null, user);});
passport.deserializeUser(function (obj, done){
done(null, obj);});
// Set Passport Initialize and Sessions
app.use(passport.initialize());
app.use(passport.session());
passport.use(new GoogleStretegy({
clientID: CREDENTIALS.google.GOOGLE_CLIENT_ID,
clientSecret: CREDENTIALS.google.GOOGLE_CLIENT_SECRET,
callbackURL:"<host>/oauth2callback"
},
function (req, accessToken, refreshToken, profile, done) {
process.nextTick(function () {
console.log(JSON.stringify(profile));
console.log(req);
var username= profile.emails[0].value.split('#');
User.findOne({email: profile.emails[0].value,username:username[0]}).exec(function (err,user) {
if(!user){
var user = new User({username: username[0]});
user.set('email',profile.emails[0].value);
user.set('FullName',profile.DisplayName);
user.save(function (err) {
if(err){
console.log(err);
profile=null;
return done(null,profile);
}else {
return done(null, profile);
}
});
}else {
return done(null, profile);
}
});
// return done(null, profile);
});
}
));
/// ROUTES !
router.get('/logout', function (req, res) {
req.session.destroy(function () {
// Google log out
req.logout();
res.redirect('/login');
});
});
//Google OAuth2
router.get('/auth/google',passport.authenticate('google', { scope: ['https://www.googleapis.com/auth/userinfo.profile','https://www.googleapis.com/auth/userinfo.email'] }));
router.get('/oauth2callback', passport.authenticate('google', { failureRedirect: '/login' }), function (req, res) {
res.redirect('/');
});
I've got a node app that operates in isolation. Without js on in the client it just operates synchronously, setting cookies with passport.js. When the client is js enabled then the auth is done via a rest route.
All seems fine, except that if I have authenticated (and have cookies set) asynchronously, but then refresh the page (or navigate synchronously to a new one [for whatever reason]), the server sends the response with new cookies that overwrite the old ones and setting the user back to being unauthenticated.
// =============================================================================
// AUTHENTICATE (FIRST LOGIN) ==================================================
// =============================================================================
// process the login form
app.post('/login', passport.authenticate('local-login', {
successRedirect: '/profile', // redirect to the secure profile section
failureRedirect: '/browse?p=0', // redirect back to the signup page if there is an error
failureFlash: true // allow flash messages
}));
app.post('/async/login', function(req, res, next) {
passport.authenticate('local-login', function(err, user, info, status) {
if (err) {
return res.send(err);
}
if (user) {
user.local = null;
return res.send(user);
} else {
return res.send(info);
}
})(req, res, next);
});
// =========================================================================
// passport session setup ==================================================
// =========================================================================
// required for persistent login sessions
// passport needs ability to serialize and unserialize users out of session
// used to serialize the user for the session
passport.serializeUser(function(user, done) {
done(null, user.id);
});
// used to deserialize the user
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
done(err, user);
});
});
// =========================================================================
// LOCAL LOGIN =============================================================
// =========================================================================
passport.use('local-login', new LocalStrategy({
// by default, local strategy uses username and password, we will override with email
usernameField: 'username',
passwordField: 'password',
passReqToCallback: true // allows us to pass in the req from our route (lets us check if a user is logged in or not)
},
function(req, email, password, done) {
// asynchronous
process.nextTick(function() {
User.findOne({
'local.email': email
}).populate({
path: 'spots comments currentLocation'
}).exec(function(err, user) {
// if there are any errors, return the error
if (err)
return done(err);
// if no user is found, return the message
if (!user)
return done(null, false, req.flash('loginMessage', 'No user found.'));
if (!user.validPassword(password))
return done(null, false, req.flash('loginMessage', 'Oops! Wrong password.'));
// all is well, return user
else
User.populate(user, {
path: 'spots.bird',
model: 'Bird'
}, function(err, user) {
if (err)
return done(err);
else
User.populate(user, {
path: 'spots.location',
model: 'Location'
}, function(err, user) {
if (err)
return done(err);
else
console.log(util.inspect(user, showHidden = false, depth = 5, colorize = true));
return done(null, user);
});
});
});
});
}));
Node App:
app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: true
}));
app.use(cookieParser());
sessionVars = {
keys: ['<removed>'],
//secureProxy: true, // if you do SSL outside of node
maxAge: 2592000000
};
app.use(session(sessionVars));
app.use(flash());
require('./../modules/auth/passport')(passport);
app.use(passport.initialize());
app.use(passport.session());
Does anyone know why?
UPDATE: The async route doesn't seem to call the serializeUser function (which explains everything!). Does anyone know how to force serialization?
If I try a direct call: passport.serializeUser(user, done) then I need the done parameter, which isn't available in the routes file (although I could pass it through);
Does anybody know if serializeUser is meant to be called as a matter of course with passport strategies?
So I found that if you use the custom form of the authenticate function:
app.get('/login', function(req, res, next) {
passport.authenticate('local', function(err, user, info) {
if (err) { return next(err); }
if (!user) { return res.redirect('/login'); }
req.logIn(user, function(err) {
if (err) { return next(err); }
return res.redirect('/users/' + user.username);
});
})(req, res, next);
});
it doesn't seem to pass it through the serializeUser function that you provide. The cookies for sessions stay in your browser and change all the time, even when you're logged out as they probably still 'tracking' your behaviour.
If you use the 'black box' version of the function:
app.post('/login',
passport.authenticate('local', { successRedirect: '/',
failureRedirect: '/login' }));
that works because it calls serializeUser automatically.
I am using passportjs for facebook authentication. Here is my facebook strategy:
passport.use(new FacebookStrategy({
clientID: config.facebook.clientID,
clientSecret: config.facebook.clientSecret,
callbackURL: config.facebook.callbackURL
}, function(accessToken, refreshToken, profile, done) {
User.findOne({ 'facebook.id': profile.id }, function (err, user) {
if (err) { return done(err); }
if (!user) {
user = new User({
name: profile.displayName,
email: profile.emails[0].value,
username: profile.username,
provider: 'facebook',
facebook: profile._json
});
user.save(function (err) {
if (err) {
console.log(err);
}
return done(err, user);
});
} else {
return done(err, user);
}
});
}));
I added the following routes:
app.get('/facebook/auth', passport.authenticate('facebook', { scope: [ 'email', 'user_about_me', 'publish_actions']}), function(req, res) { });
// I need the following fix due to this: http://stackoverflow.com/a/17015836/289246
app.get('/facebook/auth/callback', function(req, res, next) {
if (req.query && !req.query.error && req.query.error_code) {
req.query.error = true;
}
next();
},
passport.authenticate('facebook', { failureRedirect: '/facebook-auth-failure', successRedirect: '/auth-success', failureFlash: true })
);
app.get('/facebook-auth-failure', users.authFailure);
app.get('/auth-success', users.authSuccess);
My users.authFailure method is:
exports.authFailure = function (req, res) {
var error = ???
// How can I get here the error message??
res.render('auth-failure', {
error: error || 'An error has accured'
});
};
In case of facebook authentication failure, how can I get the error message (I want to display it to the user)?
Since you're using failureFlash, this should do it:
var error = req.flash('error');
I experienced many many problems and bugs and configurations issues during working with Passport. My solution was to move to Everyauth.
I don't know if this will be any use to you but I got access to flash messages this way.
When you are defining the FacebookStrategy use the passReqToCallback parameter.
passport.use(new FacebookStrategy({
clientID: facebook.getClientID(),
clientSecret: facebook.getClientSecret(),
callbackURL: facebook.getCallback(),
passReqToCallback: true
this will allow you to add the req.flash() as a parameter to the done() like so
return done(false, user, reg.flash('success', 'Sign in successfull'));
Hope that sheds some light on the situation for you or anybody else looking for help