0

I have an app that uses JWT tokens for user authorization. Now, I need to be capable of deactivating users (users won't be allowed to use the system but still exist in the database), but as a requirement for that, I need to know if the user is not logged in. Is there some kind of best practice for handling this kind of scenario?

Example: admin gets a list of users -> admin selects one user to deactivate -> the server checks if the user to be deactivated is not logged in -> if it is, don't deactivate and return an error to admin, else, deactivate and return success to admin.

The way I thought about doing this was using a smaller expiration time for the token (to be refreshed) and store the last one generated in the user's table so that I can check (with the expiration) if there has been a recent user activity.

Update: Every time a user logs in a new token is generated. There is a logout option, it blacklists the user's token so that it can't be used again.

3
  • 4
    This isn't really something that can be solved, until you dig into the justification for the odd requirement that a "logged in" user cannot be deactivated. When you figure out the motivation for that odd idea, you'll be able to figure out how to best approximate it - for example, you might accelerate the expiration of any session and prohibit new ones, or you might change the absolute block to a warning that the user has been recently active. The whole point of such authentication schemes is that you don't actually know if the user is ever going to come back with that token, or not. – Chris Stratton Mar 9 '19 at 14:10
  • 3
    It sounds like "deactivation" actually means "prevent future logins", which is kind of weird in my opinion. But if that's what you want, you can just set a flag saying that the next time the user tries to login, no token will be generated. Or am I missing something? – ChatterOne Mar 11 '19 at 10:58
1

There are several cases:

If your application doesn't have a logout button, then you might not have a well-defined concept of what it means to be logged in. In which case I'd seek clarification on whether the need can be met in terms of recent activity. If so, there's no reason to mess with expiration times, just update some table with last_activity_time = now when the user does something. (I'm saying "some table" because the question of whether it's better to add a column to the user table or to add a "recent activity" table is beyond the scope of this answer.)

If you do have a logout button, then it should be updating some table to indicate that the user isn't logged in so that subsequent requests from that user aren't accepted if accompanied by the token used to authenticate the logout request. (This assumes when they log in again they get a new token.) The token they have is still valid in the sense that your application really did issue it to them; I'm asserting that the presence of a logout button changes the app logic for "do I accept this request" to include the concept of "did they log out" rather than just "is the accompanying token valid."

If you have a logout button and all it does is wipe the client side token, then I'd argue the app is broken and would go back to the question of what it actually means to log out.

If a significant portion of the users close or abandon the browser window without logging out, then I'd push back on the "server checks if the user to be deactivated is not logged in" requirement. (In that case "logged in" might be well-defined but still not useful, so it's back to the "recent activity" idea.)

0
1

The following comes with a (big) grain of salt, because my knowledge of JWT is only theoretical, but I am trying to give a helpful answer:

You have a login process in which the credentials are checked and - based on business rules - the user is or is not allowed to log in; perhaps he was banned etc. As a positive result this user is getting a token in return, which has an issuing date as well as an expiry date; in case of a negative result the user gets - of course - no new token. The token he got authenticates the user for as long as the expiry allows. So there might be a gap between the point in time, you do not want the user to use your service and the point in time when the valid token expires.

A viable solution would be to propagate the information that tokens for a given user before a given point in time are invalid. This information has to be stored at the according servive as long as the given token is itself isn't expired:

Say your tokens live for two hours, this information could be discarded after two hours. So you prevent littering your "bad tokens"-table.

If the user visits your site before the expiry, the token is thrown as immediately away as the information is propagated through your system. If he tries to log in, he doesn't get a fresh token; the same goes of course for the refresh option.


I need to know if the user is not logged in [...] admin gets a list of users -> admin selects one user to deactivate -> the server checks if the user to be deactivated is not logged in -> if it is, don't deactivate and return an error to admin, else, deactivate and return success to admin.

What is the background for that?

Update: Every time a user logs in a new token is generated. There is a logout option, it blacklists the user's token so that it can't be used again.

Is there a reason for "blacklisting" a token instead of rendering it useless with an expiry date in the past and throwing a token away?

What information do you store in your token, if any?

0

I have an app that uses JWT tokens for user authorization. Now, I need to be capable of deactivating users (users won't be allowed to use the system but still exist in the database), but as a requirement for that, I need to know if the user is not logged in.

Why do you need to know? If the WEB API is stateless (I will assume it's) there should not be a session but the one that lasts for the entire request. That's all the "session" you will have.

If you want to deny access to users, then just invalidate the tokens.

Say you persist every JWT's signature in the DB and the expiration time. Then you load a cache with these signatures, setting up its eviction at the expiration time. In every request, before checking JWT claims, you look for the signature in the cache. If the signature is not in the cache, then reject the request. If you want to invalidate tokens manually, then remove entries from the cache yourself.

It's the client-side who knows if "it was previously authenticated" and how to behave when the server rejects any request due to authorization issues.

Of course, it doesn't block the user, it just forces the user to get a new JWT by sign in again. Blocking the user might take more actions. For example, your blocking operation might take you to set a certain flag to DISABLED or put the user ID into a blacklist, force the token's expiration and/or remove the signature from the cache. Manually.

Later on, you will check all these things in the authorization process, before checking the claims of the token. If the request doesn't pass all the validations, then proceed with an unauthorized access use-case.

If you need the user to know the reason, you can set a message in the response body.

5
  • Putting valid JWTs in a cache somewhat defeats the point of using JWTs in the first place, because it's basically a stateful session. It makes more sense to have a way to revoke keys, e.g. "any key for user 42 before 12:30 is invalid, do not trust it". – IMSoP Mar 29 at 11:29
  • The cache is just for performance and eviction. On the other hand, Im not caching "valid tokens". Just the signature. Any hash might work aswell. The goal is not validation by comparission. It's indexing. The key rejection sounds good tho. Never tried this approach. The idea around the cache is to speed up the check out since it's something to do in every request. – Laiv Mar 29 at 11:32
  • Sure, but by the time you have a list of every valid token, you might as well put the session info (user ID etc) in that data store rather than encoded in the token, unless your JWTs are really huge (a bad idea anyway). The number of valid tokens at any given time will be much higher than the number of users who recently actively logged out (an expired session doesn't need to be revoked), so just storing a revocation timestamp is much more efficient, and retains most of the benefits of the stateless JWT. – IMSoP Mar 29 at 11:37
  • Indexing expiration times does respond to one prupose. Not having to decode and validate a JWT that we know, before hand, is no longer valid (no Matter the reason). The hashing and the claim checking is costly compared to checking whether an entry exists in a cache. I usually do it this way on APIS with a high and sustained concurrency. – Laiv Mar 29 at 11:41
  • What I'm saying is that if you're checking a data store every request anyway, and it contains an entry for every valid token, then use that as a traditional session store - make the token a random string and associate user ID etc with it in the "cache". Then you never need to verify a JWT signature. The theory of a JWT is that the opposite trade-off applies: checking the signature is cheaper than checking a central list of valid tokens; or possibly just cheaper than maintaining that list. Doing both gets you the downsides of both approaches. – IMSoP Mar 29 at 11:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.