DEV Community

Discussion on: How do you handle role/permissions updates with JWT?

Collapse
 
kspeakman profile image
Kasey Speakman • Edited

If you need to know whether the user's permission changed before processing every request, then you will have to look up the information on every request, which is going to increase your latency. There's no way around it. To mitigate the increased latency, you can use something like Redis (memory-based DB cluster) to store the current user permissions so that lookups are fast. (You could also try more complicated solutions like a pub/sub notification on user changes. But this seems like really a high burden of proof of need vs complexity.)

Having the permission changes immediately reflected always costs something. Even before JWT existed, this was a known issue, so security frameworks would cache the permissions for a period of time. This led to the same issue of the user continuing to have the old permissions until the cache expired. You can look at the JWT as a cache.

The larger question is: how important is it that permission changes are immediate? For us, it is not that important. For scenarios like deactivating a user or changing user permissions, we inform the users that it may take up to an hour to take effect (which is the token/cache lifetime). Under extreme situations, like an active attack, there are nuclear options like changing signing key (so all of the existing tokens are invalidated) or shutting down the attacked service.

Lastly, I want to say that for our latest app, we have gone to a model where we no longer keep permission claims in the JWT. We keep the permission in our own database and after we read them for a particular user we cache it for a (configurable) period of time to amortize the latency cost. We do this for a couple of reasons. One is that the JWT size kept increasing as our app features increased. And it had to be sent on every request. Two is that it was awkward to manage user permissions through our auth provider, especially if we want to expose them to users to manage themselves. Ultimately we went for a scenario where the auth provider knows almost nothing about the user. It only handles the hard (or uninteresting) problems: auth, password storage, token issuance, forgot password, etc. When we create the user in the auth provider, we attach their ID to our own user. So when the token comes in, we can lookup our user permissions from their ID.

Collapse
 
sebastiandg7 profile image
Sebastián Duque G

I really like the idea of using the token just for user authentication.

Most of the times client apps UI change drastically according to user's permissions. The main reason of having the authorization updates as quick as possible in client side is because of UI/UX concerns.

Collapse
 
kspeakman profile image
Kasey Speakman

If it is part of the core business that your app is meant to solve, then I understand. (Otherwise, I wouldn't invest too much in solving it until it is proven to be a big enough support burden.) To solve it, seems like you would need to setup a pub/sub system to be notified of changes soon after they happen. From the browser maybe web sockets with long-poll fallbacks. There are numerous pub/sub options for the backend, depending on your needs.

Thread Thread
 
sebastiandg7 profile image
Sebastián Duque G

I get it. But maybe a pub/sub strategy is too much. You could define some specific (not so regular) user events in your app that triggers the authorization data update, like going from a big module to another.

Additionally, reacting to 401 Unauthorized responses could help to deal with this (401 > fetch authorization data).

Thread Thread
 
kspeakman profile image
Kasey Speakman

Additionally, reacting to 401 Unauthorized responses could help to deal with this (401 > fetch authorization data).

For sure. But the back-end will still need a way to be aware of permission changes or else recheck the permission store every request. (If you are still expecting changes to be immediate.)

That’s assuming we are targeting scalable workloads. If the service doesn’t need to scale and it also responsible for making the permission changes, then you might just be able to keep permissions loaded in memory, and update them as changes happen.