48

So here is my configuration for passport-facebook strategy:

    passport.use(new FacebookStrategy({
        clientID: ".....",
        clientSecret: ".....",
        callbackURL: "http://localhost:1337/register/facebook/callback",
    },
    facebookVerificationHandler
    ));

And here is facebookVerificationHandler:

var facebookVerificationHandler = function (accessToken, refreshToken, profile, done) { 
    process.nextTick(function () {    
        .......
    });    
};

Is there a way to access to the request object in facebookVerificationHandler?

Users are registered to my site with a LocalStrategy but then they will be able to add their social accounts and associate those account with their local accounts. When the callback above is called, the user who is currently logged in is already available in req.user so I need to access req to associate the user with the facebook account.

Is this the correct way to implement it or should I consider another way of doing it?

Thanks.

laggingreflex
  • 32,948
  • 35
  • 141
  • 196
Élodie Petit
  • 5,774
  • 6
  • 50
  • 88

3 Answers3

97

There's a passReqToCallback option, see the bottom of this page for details: http://passportjs.org/guide/authorize/

Jared Hanson
  • 15,940
  • 5
  • 48
  • 45
  • 2
    Works well to get the request object to the strategy function, but I've not been able to use it in the database callback (in my case it's nano with CouchDB). Except for the callback all information is lost. Do you have any idea on how to get the request object through to these as well? –  Dec 06 '13 at 17:18
20

Try this.

exports.facebookStrategy = new FacebookStrategy({
        clientID: '.....',
        clientSecret: '...',
        callbackURL: 'http://localhost:3000/auth/facebook/callback',
        passReqToCallback: true
    },function(req,accessToken,refreshToken,profile,done){
        User.findOne({
                'facebook.id' : profile.id
            },function(err,user){
            if(err){
                done(err);
            }
            if(user){
                req.login(user,function(err){
                    if(err){
                        return next(err);
                    }
                    return done(null,user);
                });
            }else{
                var newUser = new User();
                newUser.facebook.id = profile.id;
                newUser.facebook.name = profile.displayName;
                newUser.facebook.token = profile.token;
                newUser.save(function(err){
                    if(err){
                        throw(err);
                    }
                    req.login(newUser,function(err){
                        if(err){
                            return next(err);
                        }
                        return done(null,newUser);
                    });
                });
            }
        });
    }
);

User is a mongoose model, i save the user in DB.

NarendraSoni
  • 2,210
  • 18
  • 26
  • 3
    Best solution (because I don't have to refactor to create FbStratey on every request), thanks! I think this should be marked as the correct answer. The main code that answers the question - How to actually support getting the 'req' param in the handler function - is this section here, add the 4th JSON param and then see that you can have the 'req' param now in function signature: .... **passReqToCallback: true },function(req,accessToken,refreshToken,profile,done){** – Gene Bo Jun 28 '15 at 23:49
  • Thanks, i am happy that you found it useful. – NarendraSoni Jun 29 '15 at 02:03
  • req.login and done(null, newUser) is redundant. done(null, newUser) logs the user in. – Tim Hardy Jul 07 '17 at 13:42
16

For this reason instead of setting up the strategy when the application starts I usually setup the strategy when there is a request. for instance:

app.get(
    '/facebook/login'
    ,passport_setup_strategy()
    ,passport.authenticate()
    ,redirect_home()
);

var isStrategySetup = false;
var passport_setup_strategy = function(){
    return function(req, res, next){
        if(!isStrategySetup){

            passport.use(new FacebookStrategy({
                    clientID: ".....",
                    clientSecret: ".....",
                    callbackURL: "http://localhost:1337/register/facebook/callback",
                },
                function (accessToken, refreshToken, profile, done) { 
                    process.nextTick(function () {    
                        // here you can access 'req'
                        .......
                    });    
                }
            ));

            isStrategySetup = true;

        }

        next();
    };
}

Using this you will have access to the request in your verification handler.

ragamufin
  • 4,113
  • 30
  • 32
  • 3
    Also see: http://stackoverflow.com/questions/11784233/using-passportjs-how-does-one-pass-additional-form-fields-to-the-local-authenti – ragamufin Dec 06 '13 at 02:02
  • Does `passport` replace its old `FacebookStrategy` with this new `FacebookStrategy`? – Ishaan Taylor Apr 03 '17 at 22:44
  • This was a useful solution to me because I wanted to use `req.protocol` and `req.get('host')` in generating the `callbackURL` parameter – Jason Roman Mar 09 '18 at 21:35