Can I have several facebook passport strategies?

I want to handle the following passport-facebook related operations differently.

  • Sign up with Facebook
  • Facebook Login
  • Connect an existing Facebook account

For "registration" I want to do / check:

  • If the user already exists (based on the oauth id facebook), redirect to the input.
  • If the user already exists (based on the email address from the facebook profile), ask the user to log in via email, and then connect your facebook account.
  • Create a new user and sign it.

For "logging in" and "connecting an account" I want to perform a number of other checks / operations.

I looked at the passport documentation for facebook and the passport -facebook and a lot of related questions, but I'm still struggling with how to implement this.

How can I implement various facebook strategies (via passport) with various callbackURL and parameters?

+4
source share
1 answer

After much digging, this is what I ended up with:


Create 3 separate passport strategies.

Each of them has different names (facebookSignUp vs facebookLogIn vs facebookConnect) and different callbackURL paths (... / sign-up / clbk vs ... / log-in / clbk vs ... / connect / clbk).

// facebook strategy 1 (sign-up with facebook) passport.use('facebookSignUp', new FacebookStrategy({ clientID: FACEBOOOK_APP_ID, clientSecret: FACEBOOK_APP_SECRET, callbackURL: 'http://website/auth/facebook/sign-up/clbk' }, function(accessToken, refreshToken, profile, clbk) { return clbk(profile); } )); // facebook strategy 2 (log-in with facebook) ... // facebook strategy 3 (connect facebook to existing account) ... 

Create routes for each strategy.

Initial request route and callback after facebook authentication. Thus, 2 routes per strategy.

 var member = require('../member'); // member module controller // sign-up with facebook app.route('/auth/facebook/sign-up') .get(member.facebookSignUp); // passport redirect to facebook for authentication // sign-up with facebook callback app.route('/auth/facebook/sign-up/clbk') .get( member.facebookSignUpClbk, // parse facebook profile to create new user & check for existing account -> redirect to log-in route member.checkEmail, // check if email is already used -> throw error 'please log in with email, then connect facebook in settings' member.checkUrl, // get unique url member.signUp, // create new user & sign-in member.email.welcome, // send welcome email member.facebookRedirectDashboard // redirect to member dashboard ); // log-in with facebook app.route('/auth/facebook/log-in') .get(member.facebookLogIn); // passport redirect to facebook for authentication // log-in with facebook callback app.route('/auth/facebook/log-in/clbk') .get( member.facebookLogInClbk, // authenticate user and log-in & check if user exists (fb oauth id or email address) -> throw error 'please sign up with facebook or log in with email' member.lastLogin, // update user last login field member.facebookRedirectDashboard // redirect to dashboard ); // connect facebook profile to existing account ... // connect facebook profile to existing account clbk ... 

If the actual authentication of the passport is performed in the following files / functions.

member.facebookSignUp just calls the .authenticate () passport, which redirects to facebook.

 // member.facebookSignUp exports.facebookSignUp = function(req, res, next) { passport.authenticate('facebookSignUp', { // use the 'facebookSignUp' strategy display: null, // null = let facebook decide (or 'page' (default), 'popup', 'touch', etc) scope: [ 'public_profile', // profile returned by default, but specified here anywhere 'email', // ask for email address 'user_location' // ask for location ] })(req, res); }; 

member.facebookSignUpClbk starts after facebook authorizes the user and redirects the callback route. Everything happens here.

 // member.facebookSignUpClbk exports.facebookSignUpClbk = function(req, res, next) { // parse profile & plug into req.body for new user creation in later fxn function parseProfile(profile) { // user doc req.body = {}; // facebook profile data req.body.facebook = (profile._json) ? profile._json : {id: profile.id}; // name ... // email ... next(); } // check existing users (mongoose/mongodb) function checkUser(profile) { User.findOne({query}, function(err, userDoc) { if (err) { return res.redirect( 'http://'+req.headers.host+ '?header=Sign-Up Error!'+ '&message=We had trouble signing you up with Facebook. Please try again' ); } else if (userDoc) { // redirect to log-in fxn return res.redirect('http://website/auth/facebook/log-in'); } else { parseProfile(profile); } }); } // passport authentication function passportAuth() { passport.authenticate('facebookSignUp', function(profile) { if (!profile || !profile.id) { return res.redirect( 'http://'+req.headers.host+ '?header=Sign-Up Error!'+ '&message=We had trouble signing you up with Facebook. Please try again or sign-up via email.' ); } else { checkUser(profile); } })(req, res); } // start process passportAuth(); }; 

member.facebookLogIn, .facebookLogInClbk, .facebookConnect and .facebookConnectClbk are configured in the same way, only different logic in the "Clbk" functions depending on what I'm trying to do.


Hope this helps!

+7
source

All Articles