Question

I'm trying to use multiple LOCAL strategies with PassportJS. I'm not trying to use local, facebook, and gmail, etc. I have two sets of users stored in separate objects and I want to use a local strategy to authenticate both. As it stands, I cannot use the same local strategy for both because they have different object properties which has me querying different objects. Is there any way to do this? OR any suggestions around this would be greatly appreciated.

Was it helpful?

Solution

I don't think it's possible, because as far as I can see you need some method of 'handing off' a request to the second strategy when the first one fails, and I don't believe that's possible.

But you might be able to use one local strategy, and just try to authenticate the incoming data using both methods.

As a simple example (using Mongoose as an example database):

passport.use(new LocalStrategy(function(username, password, done) {
  Model1.findOne({ username : username }, function(err, user) {
    // first method succeeded?
    if (!err && user && passwordMatches(...)) {
      return done(null, user);
    }
    // no, try second method:
    Model2.findOne({ name : username }, function(err, user) {
      // second method succeeded?
      if (! err && user && passwordMatches(...)) {
        return done(null, user);
      }
      // fail! 
      done(new Error('invalid user or password'));
    });
  }); 
}));

For serialization/deserialization you might need to store some property in the user object that you pass to done to signify which model is required to deserialize the user.

OTHER TIPS

You can name your local strategies to separate them.

// use two LocalStrategies, registered under user and sponsor names

      // add other strategies for more authentication flexibility
  passport.use('user-local', new LocalStrategy({
      usernameField: 'email',
      passwordField: 'password' // this is the virtual field on the model
    },
    function(email, password, done) {
      User.findOne({
        email: email
      }, function(err, user) {
        if (err) return done(err);

        if (!user) {
          return done(null, false, {
            message: 'This email is not registered.'
          });
        }
        if (!user.authenticate(password)) {
          return done(null, false, {
            message: 'This password is not correct.'
          });
        }
        return done(null, user);
      });
    }
  ));

    // add other strategies for more authentication flexibility
    passport.use('sponsor-local', new LocalStrategy({
            usernameField: 'username',
            passwordField: 'password' // this is the virtual field on the model
        },
        function(username, password, done) {
            Sponsor.findOne({
                'primaryContact.username': username
            }, function(err, sponsor) {
                if (err) return done(err);

                if (!sponsor) {
                    return done(null, false, {
                        message: 'This email/username is not registered.'
                    });
                }
                if (!sponsor.authenticate(password)) {
                    return done(null, false, {
                        message: 'This password is not correct.'
                    });
                }
                return done(null, sponsor);
            });
        }
    ));

Later controller code refer to them by name.

/**
 * User Login
 */
exports.loginUser = function (req, res, next) {
    passport.authenticate('user-local', function(err, user, info) {
        var error = err || info;
        if (error) return res.json(401, error);

        req.logIn(user, function(err) {

            if (err) return res.send(err);
            res.json(req.user.userInfo);
        });
    })(req, res, next);
};

/**
 * Sponsor Login
 */
exports.loginSponsor = function (req, res, next) {
    passport.authenticate('sponsor-local', function(err, sponsor, info) {
        var error = err || info;
        if (error) return res.json(401, error);

        req.logIn(sponsor, function(err) {
            if (err) return res.send(err);
            res.json(req.sponsor.profile);
        });
    })(req, res, next);
};

Later when it comes time to serialize you user, you may want to do something like this.

// serialize
passport.serializeUser(function(user, done) {            
  if (isUser(user)) {
    // serialize user
  } else if (isSponsor(user)) {
    // serialize company
  }
});

you can use something like this for multiple local strategies

passport.use('local.one', myLocalStrategy1);
passport.use('local.two', myLocalStrategy2);
passport.use('local.three', myLocalStrategy3);

...

app.get('/login/s1', passport.authenticate('local.one');
app.get('/login/s2', passport.authenticate('local.two');
app.get('/login/s3', passport.authenticate('local.three');
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top