How to implements two strategies with passportjs

I have two model in my node/express app :

  1. User model (simple user authenticated)
  2. Manager model (user with different rights and different fields)

I want to use passport to authenticated them :

  1. User with couple : Username / Password
  2. Manager with couple : Email / Password

I correctly implemented PassportJS for the User model but now I try to do the same for Manager model.

exports.postlogin = function(req, res, next) {
    passport.authenticate('user', function(err, user, info) {
        if (err) { return next(err) }
        if (!user) {
            req.session.messages =  [info.message];
            return res.redirect('/login')
        }
        req.logIn(user, function(err) {
            if (err) { return next(err); }
            return res.redirect('/');
        });
    })(req, res, next);
};

exports.postlogin = function(req, res, next) {
    passport.authenticate('manager', function(err, manager, info) {
        if (err) { return next(err) }
        if (!manager) {
            req.session.messages =  [info.message];
            return res.redirect('/manager_signup')
        }
        req.logIn(manager, function(err) {
            if (err) { return next(err); }
            return res.redirect('/');
        });
    })(req, res, next);
};

The two strategies :

passport.use('user', new LocalStrategy(function(username, password, done) {
    UserModel.findOne({ username: username }, function(err, user) {
        if (err) { return done(err); }
        if (!user) { return done(null, false, { message: 'Unknown user ' + username }); }
        user.comparePassword(password, function(err, isMatch) {
            if (err) return done(err);
            if(isMatch) {
                return done(null, user);
            } else {
                return done(null, false, { message: 'Invalid password' });
            }
        });
    });
}));

passport.use('manager', new LocalStrategy({usernameField: 'manager_signin_email', passwordField: 'manager_signin_password'},function(manager_signin_email, manager_signin_password, done) {
    ManagerModel.findOne({ email: manager_signin_email }, function(err, manager) {
        if (err) { return done(err); }
        if (!manager) { return done(null, false, { message: 'Unknown manager ' + manager_signin_email }); }
        manager.comparePassword(manager_signin_password, function(err, isMatch) {
            if (err) return done(err);
            if(isMatch) {
                console.log('Manager login OK : ' + manager_signin_email);
                return done(null, manager);
            } else {
                return done(null, false, { message: 'Invalid password' });
            }
        });
    });
}));

The problem is for Serialize/Deserialize. For User I have this :

passport.serializeUser(function(user, done) {
    done(null, user.id);
});

passport.deserializeUser(function(id, done) {
    UserModel.findById(id, function (err, user) {
        done(err, user);
    });
});

But I don't know how to do for Manager model.

I think there is an open issue for what you want (https://github.com/jaredhanson/passport/issues/148) .

Alternatively you could change you serialize method to include information if it's user or manager not only user id and when deserializing read that info and load user/manager from proper model.

You could maybe do something like this when serializing:

if (isUser(user)) {
    // serialize user
    done(null, "user_"+user.id );
  } else if (isManager(user)) {
    // serialize manager
    done(null, "manager_"+user.id );

  }

And then check the prefix when deserializing.

In case anyone is still stumbling upon this. You can check the type of the object you are serializing. Note all there of by objects are generalized in to a PrincipleInfo object.

function PrincipleInfo(principleId, principleType, details) {
    this.principleId = principleId;
    this.principleType = principleType;
    this.details = details;
}

passport.serializeUser(function (userObjectThing, done) {
    //userObjectThing could be a User or a Sponsor
    var principleType = "user";
    var userPrototype =  Object.getPrototypeOf(userObjectThing);
    if (userPrototype === User.prototype) {
        principleType = "user";
    } else if (userPrototype === Sponsor.prototype) {
        principleType = "sponsor";
    } else if (userPrototype === Admin.prototype) {
        principleType = "admin";
    }

    var principleInfo = new PrincipleInfo(userObjectThing.id, principleType, '');
    done(null,principleInfo);
});

    passport.deserializeUser(function (principleInfo, done) {

        if (principleInfo.principleType == 'user') {
            User.findOne({
                _id: principleInfo.principleId
            }, '-salt -hashedPassword', function (err, user) { // don't ever give out the password or salt
                done(err, user);
            });
        } else if (principleInfo.principleType == 'sponsor') {
            Sponsor.findOne({
                _id: principleInfo.principleId
            }, '-salt -hashedPassword', function (err, user) { // don't ever give out the password or salt
                done(err, user);
            });
        } else if (principleInfo.principleType == 'admin') {
            Admin.findOne({
                _id: principleInfo.principleId
            }, '-salt -hashedPassword', function (err, user) { // don't ever give out the password or salt
                done(err, user);
            });
        }

    });