jaredhanson / passport-facebook

Facebook authentication strategy for Passport and Node.js.
https://www.passportjs.org/packages/passport-facebook/?utm_source=github&utm_medium=referral&utm_campaign=passport-facebook&utm_content=about
MIT License
1.3k stars 446 forks source link

profile.id undefined #185

Closed Acesonnall closed 8 years ago

Acesonnall commented 8 years ago

Hello,

So I've attempted to fix this issue for hours but to no avail. The error says:

image

And upon running in debug mode (That's also what the "profile undefined" was -- a console log): image

After doing hours of research, I can't seem to figure out what the profile field is not being sent back.

Here's my passport.js: `passport.use('facebook', new FacebookStrategy({ clientID : configAuth.facebookAuth.clientID, clientSecret : configAuth.facebookAuth.clientSecret, callbackURL : configAuth.facebookAuth.callbackURL, passReqToCallback : true, profileFields: ['id', 'emails', 'name'] },

    // facebook will send back the token and profile
    function(accessToken, refreshToken, profile, done) {

        console.log('profile', profile);

        // asynchronous
        process.nextTick(function() {

            // find the user in the database based on their facebook id
            User.findOne({ 'id' : profile.id }, function (err, user) {

                // if there is an error, stop everything and return that
                // ie an error connecting to the database
                if (err)
                    return done(err);

                // if the user is found, then log them in
                if (user) {
                    return done(null, user); // user found, return that user
                } else {
                    // if there is no user found with that facebook id, create them
                    var newUser            = new User();

                    // set all of the facebook information in our user model
                    newUser.facebook.id    = profile.id; // set the users facebook id
                    newUser.facebook.id    = accessToken; // we will save the token that facebook provides to the user
                    newUser.facebook.name  = profile.name.givenName + ' ' + profile.name.familyName; // look at the passport user profile to see how names are returned
                    newUser.facebook.email = profile.emails[0].value; // facebook can return multiple emails so we'll take the first

                    // save our user to the database
                    newUser.save(function(err) {
                        if (err)
                            throw err;

                        // if successful, return the new user
                        return done(null, newUser);
                    });
                }

            });
        });

    }));`

And my routes `/ route for facebook authentication and login app.get('/auth/facebook', passport.authenticate('facebook', { scope : ['email', 'public_profile'] }));

// handle the callback after facebook has authenticated the user
app.get('/auth/facebook/callback',
    passport.authenticate('facebook', {
        successRedirect : '/profile',
        failureRedirect : '/'
    }));`
Acesonnall commented 8 years ago

Problem solved after buckling down and debugging the entire passport facebook strategy.

Right here in strategy.js is where things matter. image

The strategy checks to see what the length of the arguments you are passing in is, which can be affected by the passReqToCallBack parameter. I had accidentally set this without adding the corresponding 'req' parameter needed, so my data was shifted (profile was stored in "done" which means verification was eliminated).

Good stuff.

libnine commented 7 years ago

Can you specify about where you placed the req parameter? I'm having an issue with this exact problem as well.

Acesonnall commented 7 years ago

No problem, so based on the image above, we see that the middleware is checking if 'self._passReqToCallback' is true. If it is, it will validate the arguments with the 'req' parameter first.

So when you want to pass the req parameter to the callback, you should set up your function as such:

 passport.use('facebook', new FacebookStrategy({
            clientID: [YOUR CLIENT ID]
            clientSecret: [YOUR CLIENT SECRET],
            callbackURL: [YOUR CALLBACK URL],
            profileFields: [YOUR FIELDS],
            passReqToCallback: true
        },

        // facebook will send back the token and profile
        (req, accessToken, refreshToken, profile, done) => {

        }));
libnine commented 7 years ago

Hmm.. so the login works, but the following fields populate under my facebook params:

email: name: undefined undefined

here's my code:

// facebook passport.use(new FacebookStrategy({ clientID: configAuth.facebookAuth.clientID, clientSecret: configAuth.facebookAuth.clientSecret, callbackURL: configAuth.facebookAuth.callbackURL, passReqToCallback: true }, function(req, token, refreshToken, profile, done) { process.nextTick(function() { if (!req.user) { User.findOne({ 'facebook.id' : profile.id }, function(err, user) { if (err) return done(err); if (user) { if (!user.facebook.token) { user.facebook.token = token; user.facebook.name = profile.name.givenName + ' ' + profile.name.familyName; user.facebook.email = profile.email;

                        user.save(function(err) {
                            if (err)
                                throw err;
                            return done(null, user);
                        });
                    }

                    return done(null, user); // user found, return that user
                } else {
                    var newUser            = new User();

                    newUser.facebook.id    = profile.id;
                    newUser.facebook.token = token;
                    newUser.facebook.name  = profile.name.givenName + ' ' + profile.name.familyName;
                    newUser.facebook.email = profile.email;

                    newUser.save(function(err) {
                        if (err)
                            throw err;
                        return done(null, newUser);
                    });
                }
            });

        } else {
            var user            = req.user;

            user.facebook.id    = profile.id;
            user.facebook.token = token;
            user.facebook.name  = profile.name.givenName + ' ' + profile.name.familyName;
            user.facebook.email = profile.email;

            user.save(function(err) {
                if (err)
                    throw err;
                return done(null, user);
            });
        }
    });
}));

app.get('/auth/facebook', passport.authenticate('facebook', { scope : 'email' }));

    // handle the callback after facebook has authenticated the user
    app.get('/auth/facebook/callback',
        passport.authenticate('facebook', {
            successRedirect : '/profile',
            failureRedirect : '/'
        }));

Not sure what i'm doing wrong..

omererbil commented 6 years ago

to avoid return undefined from name field just change your code for this : user.facebook.name = profile.displayName