Search code examples
node.jsexpresspassport.js

passport.js multiple de/serialize methods


I'm building a 2 parts login system. Where the a user will login to a main account Account model, this account will hold access to many teams Team model, and an account can have 1 user per team User model. The problem is that I can define an Account login strategy with passport but I will only be able to serialize and deserialize using Account model, but when I want to redirect or login the Account with their User specific data related to a Team I can't log them using passport. I need some ideas or solutions, maybe there's some passport strategy out there I could use. PS: think of this like a slack login system kind of works, main account (email) can hold multiple teams or chat groups with speific details on each.


Solution

  • If I understood your need correctly I believe you have two options - register multiple (de)serializers, or put more logic into your (de)serialization implementations.

    While not really documented, you can register multiple serialize and deserialize functions. If the first function is not successful it should call done('pass'); to have the execution continue to the next (de)serializer, eg. (note that the code examples are just off the top of my head):

    passport.deserializeUser((obj, done) => {
      Account.deserialize(obj)
        .then((account) => done(null, account))
        .catch((err) => done('pass'));
    });
    
    passport.deserializeUser((obj, done) => {
      User.deserialize(obj).then((user) => done(null, user))
    });
    

    You are not limited to using the apparently builtin (de)serialization of the ORM/ODM of your choice. Thus you can do any custom logic you need in the serialization functions. For example, put the model instance ID and type into an object in serialization, and use them when deserializing.

    passport.serializeUser((obj, done) => {
      if (obj instanceof Account) {
        done(null, { id: obj.id, type: 'Account' });
      } else {
        done(null, { id: obj.id, type: 'User' });
      }
    });
    
    passport.deserializeUser((obj, done) => {
      if (obj.type === 'Account') {
        Account.get(obj.id).then((account) => done(null, account));
      } else {
        User.get(obj.id).then((user) => done(null, user));
      }
    });