Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passport-Facebook authentication is not providing email for all Facebook accounts

I am using Passport-Facebook authentication.

  passport.use(new FacebookStrategy({
            clientID: 'CLIENT_ID',
            clientSecret: 'CLIENT_SECRET',
            callbackURL: "http://www.example.com/auth/facebook/callback"
        },
        function (accessToken, refreshToken, profile, done) {            
            process.nextTick(function () {                
               console.log(profile)
            });               
        }
    ));

For some of the Facebook accounts I don't get the email_id and I even tried by using a scope variable such as below, but still I am unable to get the email_id.

profileUrl : " " and ProfileFields : ['','']

like image 733
AMT Avatar asked Apr 05 '14 12:04

AMT


5 Answers

Make sure these two things are in your code:

  passport.use(new FacebookStrategy({
            clientID: 'CLIENT_ID',
            clientSecret: 'CLIENT_SECRET',
            callbackURL: "http://www.example.com/auth/facebook/callback"
            passReqToCallback : true,
            profileFields: ['id', 'emails', 'name'] //This
        },

and this:

app.get('/connect/facebook', passport.authorize('facebook', { scope : ['email'] }));

This gives you access to the following:

  • profile.id
  • profile.name.givenName
  • profile.name.familyName
  • profile.emails

The last one being an array, so use profile.emails[0].value to get the first email address of the user.

As shamim reza pointed out, you might want to check if profile.emails !== undefined because the property only exists if the user has at least one verified email address.

As Weft pointed out, you might have to use the property email instead of emails.

like image 182
Forivin Avatar answered Oct 12 '22 14:10

Forivin


When you are authenticating use something similar to this. You need to use add 'email' in the scope when you authenticate.

app.get('/auth/facebook',
passport.authenticate('facebook', { scope: ['email']}),
    function(req, res){
});

That has worked for me.

Here were a few links that helped me out.

https://github.com/jaredhanson/passport-facebook/issues/11 https://github.com/jaredhanson/passport-facebook#how-do-i-ask-a-user-for-additional-permissions

like image 44
sifxtreme Avatar answered Oct 12 '22 16:10

sifxtreme


I would like to add more information here.

While adding profileFields: ['emails'] while creating FacebookStrategy and passport.authorize('facebook', { scope : ['email'] }) solves issue for most of the users.

There are other possible reasons where you will not get user's email after authentication.

  • No e-mail address on account
  • No confirmed e-mail address on account
  • No verified e-mail address on account
  • User entered a security checkpoint which required them to reconfirm their e-mail address and they have not yet done so
  • User's e-mail address is unreachable

​ you need to make sure that your user does not have any of the issues listed above. more information can be found https://developers.facebook.com/bugs/1802930019968631/

like image 44
vinesh Avatar answered Oct 12 '22 15:10

vinesh


When passport doesn't return the profile.emails, profile.name.givenName, profile.name.familyName fields, or if they are missing, you can try to parse the https://graph.facebook.com/v3.2/ url, although you still need a token. You access the url, with of course a valid token, like:

https://graph.facebook.com/v3.2/me?fields=id,name,email,first_name,last_name&access_token=

It outputs a JSON response like:

{
   "id": "5623154876271033",
   "name": "Kurt Van den Branden",
   "email": "kurt.vdb\u0040example.com",
   "first_name": "Kurt",
   "last_name": "Van den Branden"
}

Install the request module ($ npm install request --save), to be able to parse a JSON url and in your passport.js file:

const request = require("request");

passport.use(new FacebookStrategy({
        clientID        : 'CLIENT_ID',
        clientSecret    : 'CLIENT_SECRET',
        callbackURL     : "https://example.com/auth/facebook/callback"
    },
    function(req, token, profile, done) {

        let url = "https://graph.facebook.com/v3.2/me?" +
                  "fields=id,name,email,first_name,last_name&access_token=" + token;

        request({
            url: url,
            json: true
        }, function (err, response, body) {
              let email = body.email;  // body.email contains your email
              console.log(body); 
        });
    }
));

You can add a lot of other parameters to the url, although some of them require user permission to return values. You can play with it on: https://developers.facebook.com/tools/explorer/

like image 32
Kurt Van den Branden Avatar answered Oct 12 '22 16:10

Kurt Van den Branden


Make sure you're providing the scope parameter into the first .authenticate() call, not the callback.

Like this:

router.get("/auth/facebook", passport.authenticate("facebook", {
    scope: [ "email" ], // scope goes here, not below
}));

router.get("/auth/facebook/callback",
    passport.authenticate("facebook", {
        successRedirect: "/",
        failureRedirect: "/login",
    }),
);
like image 40
LachoTomov Avatar answered Oct 12 '22 15:10

LachoTomov