Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

API: Cache user for optimized authentication #207

Closed
rajdip-b opened this issue May 11, 2024 · 10 comments · Fixed by #386
Closed

API: Cache user for optimized authentication #207

rajdip-b opened this issue May 11, 2024 · 10 comments · Fixed by #386
Assignees
Labels
difficulty: 2 foss hack Clustering all the curated issues for Foss Hack 2024 help wanted Extra attention is needed priority: medium scope: api Everything related to the API type: enhancement New feature or request

Comments

@rajdip-b
Copy link
Member

Description

keyshade uses stateless cookie-based authentication to let users in. In the long run, this will impose a strain on our database since we will have over 100qps. To optimize this, we would like to cache our user data during authentication.

Solution

In auth.guard.ts, if the authentication is successful, we fetch the user details and set it in the current session. We would also like to cache this data. We will be using the key structure user-<userId>.

  • Import Redis in auth.guard.ts:
    @Inject(REDIS_CLIENT) readonly redisClient: {
        publisher: RedisClientType
    },
  • Try to fetch the user from redis by the user-<userId>. If it's null, fetch from the database by email.
  • JSON.stringify() the data retrieved, and set it in cache as userId -> userObject(stringified)
  • In user.serviec.ts, whenever a user is updated, fetch the cached user, and update the value of the cache.

Additional context

Relevant files can be found in auth and user module.

@rajdip-b rajdip-b added type: enhancement New feature or request help wanted Extra attention is needed scope: api Everything related to the API priority: medium labels May 11, 2024
@rajdip-b rajdip-b added difficulty: 2 foss hack Clustering all the curated issues for Foss Hack 2024 labels Jun 6, 2024
@Z-xus
Copy link
Contributor

Z-xus commented Jul 18, 2024

/attempt I'd like to work on this issue for fosshack.

Copy link

Assigned the issue to @Z-xus!

@rajdip-b
Copy link
Member Author

The approach isnt correct.

  1. We generally set that cache after we have fetched the user from the db. In your case, you are using an additional if block to check if the user is not null or not, which has already been verified in the previous step
  2. When we try to fetch the user from prisma, we would first like to check if the user is present or not in the cache before we move to the db call:
    user = await this.prisma.user.findUnique({
    where: {
    id: payload['id']
    }
    })
    } catch {
    throw new ForbiddenException()
    }
  3. It is expected that the cache will be created only once, but that shouldn't affect the tests (shouldn't fail them). The guards are working as expected.

@Z-xus
Copy link
Contributor

Z-xus commented Jul 25, 2024

My logic was to set cache only in auth module after successfully logging in because using cache there could sacrifice integrity of data

I was just setting a string so I'll try now with hashmap so it will be well segregated as well, hopefully that would work out.

Also, should I create a service for this caching? it seems to be used both times like setting after login and setting when user updates.

I appreciate your time and help.

@rajdip-b
Copy link
Member Author

A cache service would be highly appreciated if you can make one. Maybe, you can create a separate module for that and export it globally.

Also, as for your concerns regarding data integrity, those are valid. So in that case, at the very bottom of the function is a line that sets the user in the request body. You can implement the cache put operation just before that line.

@Z-xus
Copy link
Contributor

Z-xus commented Jul 26, 2024

When I try caching the user after successful login in the auth.service.ts it is working as expected. Should I go ahead with it? It seems that using otp and cookie, something about logging in auth guard is getting cached, I can't find out why
image

image

@rajdip-b
Copy link
Member Author

I think adding the cached user in this place works aswell. But then, the main use of cache is in the auth guard before we try to fetch the user from db. It wont make much sense if we just add the cache and not use it.

@Z-xus
Copy link
Contributor

Z-xus commented Jul 26, 2024

That's exactly the case I was referring to when I said data integrity, If a user{} cache is sent when trying to login a user, when an admin has deleted the user, then it would still allow the user to be logged in.. regardless of being deleted.

@Z-xus
Copy link
Contributor

Z-xus commented Jul 26, 2024

we fetch the user details and set it in the current session

From infering this, My approach was to only set user in cache when they log in and then use the cached user for subsequent get requests made from user service/s.

@rajdip-b
Copy link
Member Author

when an admin has deleted the user, then it would still allow the user to be logged in.. regardless of being deleted.

For now, admin routes are disabled. And even if the admin deletes the user, we would also delete the user from the cache so it wont be an issue.

My approach was to only set user in cache when they log in and then use the cached user for subsequent get requests made from user service/s.

As far as the scope of the issue is concerned with, we just want to use the cache in auth guard while authentication. Later on, we can add more such cache functions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
difficulty: 2 foss hack Clustering all the curated issues for Foss Hack 2024 help wanted Extra attention is needed priority: medium scope: api Everything related to the API type: enhancement New feature or request
Projects
Status: Done
2 participants