Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

passport-facebook - cant get about_me and email profile fields

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: enter image description here

I am sure this is some rookie mistake, but I just can't figure it out myself...

like image 567
omerkarj Avatar asked Nov 29 '13 18:11

omerkarj


2 Answers

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'}));
like image 127
miksiii Avatar answered Oct 21 '22 08:10

miksiii


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

like image 31
gerasalus Avatar answered Oct 21 '22 06:10

gerasalus