I am trying to establish a login system for my app using passport-facebook. everything goes well except for the 2 fields that are getting undefined back from the request.
I will post my entire code for the login procedure, since I haven't seen a lot of info about it here even though there are a lot of question in the matter.
this is the configuration in app.js
var passport = require('passport');
var FacebookStrategy = require('passport-facebook').Strategy;
passport.serializeUser(function(user, done) {
done(null, user.facebookId);
});
passport.deserializeUser(function(id, done) {
routes.findUserById(id, function(err, user) {
done(err, user);
});
});
passport.use(new FacebookStrategy({
clientID: FACEBOOK_APP_ID,
clientSecret: FACEBOOK_APP_SECRET,
callbackURL: FACEBOOK_CALLBACK_URL,
profileFields: ['id', 'displayName', 'link', 'about_me', 'photos', 'email']
},
routes.handleLogin
));
using passport initialize and session
app.use(passport.initialize());
app.use(passport.session());
actual request handling, notice I am using the correct scope
app.get('/auth/facebook', passport.authenticate('facebook', { scope: ['user_about_me', 'email'] }));
app.get('/auth/facebook/callback', passport.authenticate('facebook', { successRedirect: '/', failureRedirect: '/error' }));
and this is my user creation function in the router
exports.handleLogin = function(accessToken, refreshToken, profile, done) {
db.userCatalog.findOne({ facebookId: profile.id }, function(err, existingUser) {
if (err) {
return done(err);
}
else {
if(existingUser) {
console.log('User: ' + existingUser.name + ' found and logged in!');
done(null, existingUser);
}
else {
new db.userCatalog({
name: profile.displayName,
facebookId: profile.id,
link: profile.link,
picture: profile.photos[0].value,
bio: profile.about_me,
email: profile.email
}).save(function (err, data) {
if (err) {
return done(err);
}
else {
console.log('New user: ' + data + ' created and logged in!');
done(null, data);
}
});
}
}
});
};
and the result when creating a new user after finishing the login procedure:
I am sure this is some rookie mistake, but I just can't figure it out myself...
Facebook returns some of the default attributes. If you want to access more details about client's profile you would have to declare it under the FacebookStrategy
:
passport.use(new FacebookStrategy({
clientID: "...",
clientSecret: "...",
callbackURL: "...",
profileFields: ['id', '...', '...', 'photos', 'emails']
}, ...
So once you declare the attributes you would like to receive from Facebook, when someone try to log into your system he will be asked to share his photos or emails with you/your app. Once he approve this you can access its values:
profile.photos[0].value,
profile.emails[0].value,
...
For emails, sometimes it is useful to change:
passport.authenticate('facebook');
To this:
passport.authenticate('facebook', { scope: 'email'}));
In the profileFields you shoul use emails (plular) instead of email (singular):
profileFields: ['id', 'displayName', 'link', 'about_me', 'photos', 'emails']
This is noted in the facebook-passport documentation README.md:
profileFields parameter which specifies a list of fields (named by Portable Contacts convention)
And you can find Portable Contacts conventions for passportjs here
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With