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.
Passport's middleware is built in a way that allows you to use multiple strategies in one passport.
Strategies are responsible for authenticating requests, which they accomplish by implementing an authentication mechanism. Authentication mechanisms define how to encode a credential, such as a password or an assertion from an identity provider (IdP), in a request.
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 } });
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With