Can the callback for facebook-pasport be dynamically constructed?

When using facebook-passport the usual thing to do is to specify the redirect_uri in the constructor of the FacebookStrategy thst you use, something like this:

passport.use("facebook", new FacebookStrategy({
    //TODO: Correctly configure me
    clientID: "XXXXXXX"
  , clientSecret: "XXXXXXXXX"
  , callbackURL: "http://localhost:3007/auth/facebook/callback"
  },
  function(accessToken,refreshToken,profile,done) {
    User.findByFacebookId(profile.id, function(err,user) {
      if(err){ return done(err);}
      if(!user){ return done(null,false)}
      return done(null, user);
    });
  })
);

Then you would set up routes like this:

app.get('/auth/facebook/login', passport.authenticate('facebook') );
app.get('/auth/facebook/login_callback', passport.authenticate('facebook', {
    successRedirect:"/login_ok.html"
  , failureRedirect:"/login_failed.html"
  }
))

Is it possible to change the callback url so that it contains information from parameters passed to the initial login call?

NOTE: This question is more for preserving info that took me a while to work out, to avoid others going down the same paths.

Answers


I found the answer using some info found here https://github.com/jaredhanson/passport-facebook/issues/2 and through digging through the way the passport oauth2 component determines callback uris, and information about passport custom callbacks at the bottom of this page http://passportjs.org/guide/authenticate/.

Here's an example that maps calls to /auth/facebook/login/1234 to use the callback /auth/facebook/login_callback/1234

app.get('/auth/facebook/login/:id', function(req,res,next) {
  passport.authenticate(
    'facebook', 
     {callbackURL: '/auth/facebook/login_callback/'+req.params.id }
  )(req,res,next);
});

app.get('/auth/facebook/login_callback/:id', function(req,res,next) {
  passport.authenticate(
    'facebook',
     {
       callbackURL:"/auth/facebook/login_callback/"+req.params.id
     , successRedirect:"/login_ok.html"
     , failureRedirect:"/login_failed.html"
     }
   ) (req,res,next);
 });

@OMGPOP, here you can pass in query params into your callbackUrl.

var Passport = require('passport');
var FacebookStrategy = require('passport-facebook').Strategy;
const Router = require("express").Router();
var fbConfig = {
  display: "popup",
  clientID: "YourFbClientId",
  clientSecret: "YourFbClientSecret",
  callbackURL: "http://localhost:8686/auth/facebook/callback",
  profileFields: ['id', 'name', 'gender', 'displayName', 'photos', 'profileUrl', 'email']
}

Passport.use(new FacebookStrategy(fbConfig,
  function(accessToken, refreshToken, profile, callback) {
    return callback(null, accessToken);
  }
));

Router.get("/auth/facebook", function(req, res, next) {
  var callbackURL = fbConfig.callbackURL + "?queryParams=" + req.query.queryParams;
  Passport.authenticate("facebook", { scope : ["email"], callbackURL: callbackURL })(req, res, next);
});

Router.get("/auth/facebook/callback", function(req, res, next) {
  Passport.authenticate("facebook", {
    callbackURL: fbConfig.callbackURL + "?queryParams=" + req.query.queryParams,
    failureRedirect: "/login",
    session: false
  })(req, res, next) },
  function(req, res) {
  console.log(req.query.queryParams);
  //do whatever you want
});

Check out my blog for more information: http://blog.pingzhang.io/javascript/2016/09/22/passport-facebook/


I was struggling to do this specifically with Angularjs, and wanted to redirect back to the same url that the login was initiated from.

My solution was to create a route in Angularjs that just implements a location back. I know this does not specifically answer the question, but I thought it would be helpful for anyone looking to do the same.

On the server:

app.get('/auth/facebook/', passport.authenticate ('facebook'));

app.get('/auth/facebook/callback', function (req, res, next) {
    var authenticator = passport.authenticate ('facebook', {
            successRedirect: '/fbcallback',
            failureRedirect: '/'
    });

    delete req.session.returnTo;
    authenticator (req, res, next);
})

Angular router:

when('/fbcallback', {
    template: "",
    controller: 'fbCtrl' 
}).

Angular controller:

app.controller("fbCtrl", function () {
    window.history.back();
});

You could probably do some other client side routing in the controller as well.


Need Your Help

Workflow foundation 4 receives out-of-order requests and fails with key xx was not associated to an instance

workflow workflow-foundation-4 workflow-foundation workflowservice

I have a long running workflow service which uses correlation. The client of this service sends two requests in rapid succession. The message pattern for all receive activities is one-way. The bind...

Android: Set Pc as an android USB Host device to test android phone app in USB accessory mode

android usb adk

I am creating an app (running in USB accessory mode) that will recognise when a specially made device (that I am also working on) is plugged in and connect to it.