0

I am running a NodeJS express application with a PostgreSQL DB. I am using node-cache module as the store for session management in express.

The app has a user management scheme which consists of two types of users, a common user and an Admin. An admin can perform all the tasks that a common user can. In addition to that, admin can add/remove users from the app and also grant/revoke admin rights to/from users. So here comes my problem:

If an admin removes user X from the tool while user X is still logged in, then on the next request that user X sends to the server, he must be automatically logged out. Similarly, if an admin revokes admin rights of user Y while he is still logged in, then on next hit to server user Y should be automatically logged out.

After some research I came up with two ways of implementing this:

1) Authorize every request - i.e. write a middleware that will query the database and check if the user still has tool access rights. But this approach has the overhead of one additional DB hit for every request. This, I think, is a significant overhead because in my app users are not removed frequently and also the probability of an user being removed when he is already logged in is small.

2) Don't authorize every request. Instead, when user's tool access is removed, delete that user's session (if any) from the cache. So when that user sends a request, he will be logged out since his session no longer exists. However, doing this is not so straightforward since node-cache (or even Redis) does not have any 'delete by value' function. To do this I'll have to search through all the keys in the cache, find the ones that have value same as userID of user whose session needs to be removed and then delete those sessions.

I would like to know which approach is better and efficient or if there is a third and a better approach.

Basavraj
  • 43
  • 1
  • 7
  • Welcome to StackOverflow!! Please describe your question in more detail with more insights like explaining the actual task you want to accomplish, add you erroneous code snippet and what all resolutions you actually tried already to eradicate the issue. Make a note to add corresponding tags and format your code before pasting here. For more details, visit StackOverflow's guidelines including https://stackoverflow.com/help/how-to-ask. – Kapil Raghuwanshi Jun 11 '20 at 06:10

1 Answers1

0

1)I would not recommend anyone to go with the first approach. A DB hit for every request becomes a significant overhead when I scale up. Also, it will make me query the DB even if I am not doing any DB operation (CRUD) but just requesting for some resource (say a web-page).

2)Compared to the first approach, my second method seems somewhat better. However, search by value has a complexity of O(n). So as I scale up, it is going to take more time. Also this approach kind of introduces a race condition. Imagine a scenario where I remove access of a user by updating the DB and then proceed to remove the users session in the cache. If the number of users is large then there is a remote possibility that the user does some unauthorized action after his access is removed but before his session is made invalid.

I have come up with a few more solutions for this problem:

3)Store user id as the key and session id as the value. However, for this I will have to ensure that my user ids are unique. This also has the drawback that at any given time a user can have only one session active. Ex. If the user is logged in and yet he logs in again from another machine/browser then all his older sessions will be invalidated.

4)Create custom session ids by appending user id to the session id. Then I can search the keys by specifying a pattern. This feature is available in Redis though it is not recommended to be used in production code. This feature is not available in node-cache module that I am using. Nevertheless, its complexity still remains O(n).

5)Use Redis sets to store all session ids of an user against his user ID. However I still have to store session ID vs userID to maintain individual lifetimes of sessions. When user access is removed, I can use the set to retrieve all user session ids and use them to delete all sessions from the cache. Drawback is every time user creates a new session/logs out, the set as well as the hash both should be updated. Also, the set should be updated when a session expires.

6)Store a field in the DB indicating if the user is logged in and an additional field that includes a list of his active sessions. This way I can check if the user is logged in and if yes then retrieve all his session ids and then delete them from the cache. Similar to method 5.

Basavraj
  • 43
  • 1
  • 7
  • I'm facing the same problem and surprised how little resources there are addressing this, for a problem I think is fairly common. – Hamza May 17 '21 at 14:44