passport-facebook - cant get about_me and email profile fields

omerkarj picture omerkarj · Nov 29, 2013 · Viewed 13.1k times · Source

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...

Answer

miksiii picture miksiii · Jan 25, 2015

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'}));