passport-facebook: email is not returned

Hi,

I’m using nodejs and expressjs with passport-facebook for user to signup account with fb account. I found a facebook user account is not returning the email. The user don’t signed up with the Phone number instead. Only email is saved in the account contact. In addition, the email has been verified. I don’t know what is problem. Anyone has an idea?

My strategy

passport.use(new FacebookStrategy({
  clientID: facebookConfig.clientID,
  clientSecret: facebookConfig.clientSecret,
  callbackURL: facebookConfig.callbackURL,
  profileFields: ['id', 'displayName', 'name', 'gender', 'profileUrl', 'emails', 'photos'] // also 'email' is not working
  },
  function facebookHandler(accessToken, refreshToken, profile, cb) {
    if (!profile.emails || !profile.emails[0].value || !profile._json.email) {
      throw new UnprocessableEntity('No Email in Facebook');
    }
    let email = profile.emails[0].value || profile._json.email;

    User.findOne({
      where: {externalId: profile.id}
    })
    ...
  }
));

About this issue

  • Original URL
  • State: open
  • Created 8 years ago
  • Reactions: 4
  • Comments: 16

Most upvoted comments

You need to do the following when authenticating: passport.authenticate('facebook', {scope: 'email'}) Then, in your FacebookStrategy, request profileFields: [...'email'...]

Try it

passport.use('facebook', new FacebookStrategy({
  clientID        : secret.facebook.clientID,
  clientSecret    : secret.facebook.clientSecret,
  callbackURL     : secret.facebook.callback,
  profileFields   : secret.facebook.profileFields
},

For me this happens when users have restricted the visibility of their email address to only themselves.

I used the following and it worked:

passport.use(new FacebookStrategy({
  clientId: ...,
  clientSecret: ...,
  callbackURL: ....,
  profileFields: ['id', 'displayName', 'email', 'first_name', 'middle_name', 'last_name']
}))

+1, requesting both in scope

passport.authenticate("facebook", {
   failureRedirect: "/login",
   scope: ["email"] ...

and profileFields:

profileFields: ['id', 'email', 'name'] ...

Hi, I am having the same issue. Please see my code below. Not being able to request additional permissions… Any suggestions?

router.get(‘/auth/facebook’, passport.authenticate(‘facebook’, { scope: [‘email’]}));

passport.use(new FacebookStrategy({ clientID: ///// clientSecret: //// callbackURL: “http://localhost:8000/auth/facebook/callback”, profileFields: [‘id’, ‘email’, ‘displayName’, ‘photos’] },

After checking the official facebook APIs, it seems that passport is broken… or there’s something I don’t get.

Here’s a working url created by hand using the facebook docs (paste it in the browser adding your app id and you’ll see the popup):

https://www.facebook.com/v2.8/dialog/oauth?client_id=your_app_id&redirect_uri=http://localhost:3000/auth/facebook/callback&scope=public_profile,email

screen shot 2017-02-15 at 20 14 11

And here’s the url that passportjs generates (passing scope: ["public_profile", "email"] ) :

https://www.facebook.com/dialog/oauth?response_type=code&redirect_uri=http%3A%2F%2Flocalhost%3A3000%2Fauth%2Ffacebook%2Fcallback&client_id=your_app_id

screen shot 2017-02-15 at 20 14 43

Clearly the scope doesn’t get appended to the url, now we should investigate why and what’s the right way to add scope to the request. … maybe looking at the passport.authenticate() function in the source code could help?

@rsnider19 do you know something more?

You can use specified strings in this URL https://developers.facebook.com/docs/facebook-login/permissions#reference-default

Below is a snippet for strategy configuration

const { Strategy } = require('passport-facebook');
const FacebookStrategy = Strategy;

exports.facebookStrategy = new FacebookStrategy(
  {
    clientID: process.env.FACEBOOK_CLIENT_ID,
    clientSecret: process.env.FACEBOOK_CLIENT_SECRET,
    callbackURL: process.env.FACEBOOK_CALLBACK_URL,
    profileFields: [
      'email',
      'name',
      'displayName',
      'picture' ,
      'name_format',
      'short_name',
    ]
  },
  function(accessToken, refreshToken, profile, done) {
    done(null, profile);
  }
)

@rsnider19 Thanks man… Your solution works… Guys go for it…

@rsnider19 , Thanks man your solution worked.