3
5 Comments

Best practice for session verification on consequent requests after login

I'm working on a multi role Node Application which uses express-session, Redis and MongoDB. The application has a primary account under which there can be multiple users from different accounts with corresponding roles who can be logged in at one time.

The database has documents with many to many relations. When a user is logged in, then the session would exist for some definite time. I'm using middleware to verify the user for any subsequent requests to the API after they have successfully logged in.

Let's say two users are working with the documents under the same account and their sessions were already created some time before. What's the best practice to verify if the account still exists for other user if one user deletes the account.

I see two scenarios :-

  1. Check if the account exists on every request in the middleware. I'm just worried about the load it would put on the database. As every request that comes in would first need the account to be verified if it exists or not.
    Instead of verifying in the middleware.

  2. Checking if the account exists when updating the documents. In this scenario i would be putting repeatable logic to verify existence of account when ever someone tries to find/create/update/delete any document or subdocument that exists within the account.
    What do you guys think is the efficient way to implementing account existence verifying after a session is created. My session collection exists in Redis and documents in MongoDb

  1. 2

    As the IAMaaS provider Authress, I can tell you what we do for our clients. Our recommendation is two fold:

    • Cache the lookup for userId => account in your authorizer for the lifetime of the JWT access token
    • On account (or really any parent resource deletion), the user will still have access for the remaining lifetime of the token, but after that they'll lose access.
    • On account deletion since this is the highest level for the user, log the user out, this will force the refresh of the user token which aligns the caches to the new token.

    Optionally with our service, we allow immediate cache invalidation on permissions changes for a specific user, which makes it easier to handle subsequent requests.

    Further, I will suggest the following additions:

    • Let the users create as many resources as they want in the time between account deletion and token revocation
    • Some time after token revocation, go back and delete all the resources for the account in your DB.

    Having a multi-pronged strategy to handle issues like this helps to greatly reduce problems that will come up.

    I hope that all makes sense. That's also a lot to implement correctly, and sometimes difficult to get right, so I feel like the obligatory Are you sure you want to build your own authorization is required here. :)

  2. 1

    I did not understand how accounts are related with each other. can you please elaborate it.

    1. 1

      So the collections in the database are like:-

      Account = {
      _id : accountID
      users : [
      userID1,
      userID2,
      ....
      ]
      }

      User = {
      _id : userID
      account : accoundID,
      name,
      }

      On every new registration an entry in account and user collection is created.
      An account is associated to super user who registered for the account initially. He/she can add other users with different roles like admin, contributor to his/her account etc. Does it make sense?

      1. 1

        I see, I think what you are trying to achieve here is a multi-tenancy behavior.

        For the source of truth - Collection X can rely upon Collection Y but at the same time, Collection Y can not rely upon Collection X.

        So, I'd suggest that you add one more collection to avoid circular dependency.

        • Users
          All the users will be part of this collection.
        • Entity
          To manage the super users
        • Roles
          To manage the permissions

        There are few ways to create a super user.

        • Once users signup they create an entity and they are the owner of that entity.
        • Or as a system owner you generate the super users from your dashboard.

        As a superuser

        • A user can add an existing user to their entity with a specific role.
        • A user can invite a new person to join the platform. And once they join they assigned to the specific entity.

        To manage this Roles collection would be useful.
        A very rough schema example for roles collection

        {
          user_id: UserId,
          entity_id: EntityId,
          role:  'ADMIN',    // 'CONTRIBUTOR'
          permission: ['x', 'y']  // for more granular control you can also manage permission for roles.
        }
        

        For permissions, you have to rely on the roles collection. you should not rely on Redis cache.

        Whenever users perform some action you have to check if the user has the right permission or role to perform that action.

        const has_permission = check_permission(userid, entityid, role);
        

        This is a very basic example of multi-tenancy. Of-course you have to fine-tune it for your usercase.

        1. 1

          Thanks for the feedback on the collections! So regarding permission, i am relying on the database but i'm not sure at what point the verification should happen. That's where in have put those two scenarios in the original question.

Trending on Indie Hackers
After 10M+ Views, 13k+ Upvotes: The Reddit Strategy That Worked for Me! 42 comments Getting first 908 Paid Signups by Spending $353 ONLY. 24 comments I talked to 8 SaaS founders, these are the most common SaaS tools they use 20 comments What are your cold outreach conversion rates? Top 3 Metrics And Benchmarks To Track 19 comments Hero Section Copywriting Framework that Converts 3x 12 comments Join our AI video tool demo, get a cool video back! 12 comments