Search code examples
javascriptnode.jsexpresspassport.jspassport-facebook

How to get profile data in complex case using passport-facebook in node.js


I'm using passport-facebook, but this way -

app.get('/oauth/facebook', passport.authenticate('facebook', {}));

doesn't fit my requirements, cause I need to save data in the session. It won't work if I just put passport.authenticate in another function, like this:

app.get('/oauth/facebook', function (req, res, next) { 
    passport.authenticate('facebook', {});
}); // doesn't work

But it works if I call this function, like this:

const fbAuth = (req, res) => {
    req.session.isRegisterUser = req.query.isRegisterUser || false;
    req.session.regUserId = req.params.id > 0 ? req.params.id : null;
    req.session.redirectUrlAfterSignIn = req.query.redirectUrl ? req.query.redirectUrl : null;

    return passportFacebook.authenticate('facebook', {}, function() {
        // NEVER called
        console.log('auth cb');
    });
};

// this is the only way I could pass (req, res)
router.get('/oauth/:id/facebook', 
    (req, res) => fbAuth(req, res)(req, res));

It doesn't call third parameter function, but it redirects. So after this, it goes to the callback function:

const fbCb = (req, res) => {
    return console.log(req.session.regUserId);
};

router.get('/oauth/facebook/callback', (req, res) => fbCb(req, res)(req, res));

And this works, but how can I get profile data? Cause in my URL there is only parameter code, which is access_token if I understand correctly.

I initialise Strategy the same way as in documentation:

const passport = require('passport');
const Strategy = require('@passport-next/passport-facebook').Strategy;

passport.use(new Strategy({
        clientID: process.env.FACEBOOK_APP_ID,
        clientSecret: process.env.FACEBOOK_SECRET,
        callbackURL: 'http://localhost:3001/api/oauth/facebook/callback',
        graphApiVersion: 'v3.1',
        // scope: ['email']
    },
    function(accessToken, refreshToken, profile, cb) {
        // NEVER called
        console.log(`accessToken`, accessToken);
        console.log(`profile`, profile);
        return cb(null, profile);
    }
));

passport.serializeUser(function(user, done) {
    done(null, user.id);
});

passport.deserializeUser(function(id, done) {
    return models.User.findById(id).then(user=>{
        done(null, user);
    }).catch(function (err) {
        done(null, null);
    });
});

module.exports = passport;

But function(accessToken, refreshToken, profile, cb) never called. However, I need an access to request, that I can check my session data, so I need all this in my callback function, not here.

So, I'm a bit frustrated, why it become so complex. To solve this, probably I can get data by URL https://graph.facebook.com/v3.1/me?... and parse JSON. But why I need this library then?!

You can find all code here


Solution

  • I found out that it's necessary to call passportFacebook.authenticate second time to call callback. And it's possible to do this inside function, the only thing that you should return the result of a function passportFacebook.authenticate (call it). Final code