Instead of `SELECT isValid from tokens where token="<TOKEN>"`, why not `SELECT user from sessions where session="<COOKIE-SESSION>"`?
If you check against a single constant in the backend, are you invalidating all JWTs for all users whenever you want to invalidate only one? Even if you keep a blacklist of invalidated JWTs, how do you keep it up to date? How do you distribute it? What happens if the blacklist becomes unavailable for whatever reasons?
Changing the static token causes all JWT token verifications to fail (since the token is stored in the JWT),so requires each user re-auth on the next request. It's a manual fail-safe to invalidate stored sessions.
This, of course can spike load considerably in the period immediately after, so if that's a problem, you can always use multiple tokens based on some criteria, such as one matching the first letter of the username, or the user id mod some value, so split your user into N chunks that each have their own invalidation token, so you only have to invalidate the sessions of 1/N users.
So if a single user's token gets compromised, you force ALL users to log in again?
All the token does is force some extra level of scrutiny. It doesn't mean the JWT has to be invalidated,but it does give you the ability to selectively invalidate specific ones for the cost of extra DB load once for all affected users.
Anyway, I'm still not convinced because when it comes to security I feel like it's a better idea to walk the well-trodden path, rather than invent new and exciting mechanisms. JWTs are useful for other stuff, but using them for security requires increasing back-end complexity quite a bit.
User gets banned or privileges revoked? Fine, revoke the master token on the authentication server and after 5 minutes at the latest, the user is locked out as he cannot get new valid short-lived tokens.
Sessions aren't difficult - as long as you stick to one language and environment (e.g. PHP). But as soon as you throw in for example Java to communicate with a SAP backend (as an online-shop system might need to), nodejs for a "support/sales chat" system and whatever, a JWT scheme is easier to implement.
This is exactly the ability which JWT lacks.
You can, of course, combine a session ID (checked against a DB) with a short-lived token (stateless, with expiration time encoded). This will allow to only check the session against a DB if, say, more than 30 seconds has passed since the previous check. It helps with spiky traffic, and still allows to invalidate a session soon enough for practical reasons.
That might be fine for a lot of use cases. But anything that can steal money using that token and 5 minutes is a very long time indeed.
But anything that can steal money using that token and 5 minutes is a very long time indeed.
Then implement a check for the token in destructive operations. Should keep the performance impact pretty low.I believe people are downvoting you because you may have overlooked the processing that must happen on the server to encode the token in the first place.
Everything from there goes to "Congratulations! You've just re-invented sessions (only with a less battle-tested implementation) and gained nothing in the process"
(Sarcasm is from the author's post, not mine!)
Also, in my case, "your blacklisting/revocation server goes down" means the whole application is down anyway, so that's kind of a moot point.
You may disagree, and there are valid reasons to avoid JWT. I'm just saying that under the right circumstances, it can be useful.
[1] The author claims that JWT isn't any easier, but then later says things like "Expiration can be implemented server-side just as well, and many implementations do". That's true, but it is something extra you have to implement yourself, i.e., not easier (for that feature at least).
So just use a session library with expiration implemented, don’t take one without and add it on yourself.
For some of my particular use cases[2], I happen to prefer the JWT approach (despite all the points given in the article, and after auditing the libraries used). For others, I definitely prefer traditional session tokens.
[1] Just because it’s been implemented by someone else, the complexity of that code still falls on you - especially so with something as critical as authentication. It’s not automatically “easy” because someone else implemented it; I’ve seen some pretty terrible security issues in both JWT libraries (e.g., insecure defaults) and framework-provided session management libraries.
[2] Guess what? If you have tens or hundreds of millions of users, managing sessions and expiration can be a bit of a pain. Example: to keep things performant, you'll want to periodically clean up your session store (rather than just invalidating at lookup). Congratulations - now you have a background worker and the complexities of dealing with that at scale. Point is, even with nice framework-provided libraries, managing session tokens on the server can add considerable complexity.
The author does sound negative, but doesn't claim JWTs are categorically bad; he actually mentions cases where JWTs are useful: when they are used as single-use tokens. The author claims JWTs as sessions are too problematic to be useful.
> I’ve seen some pretty terrible security issues in both JWT and framework-provided session management libraries.
It seems to me the author is arguing JWTs (used as sessions) are more error prone and less battle tested than traditional session management. So if you've seen terrible security issues...
As for session cookies: like the author says, cookies are a storage medium and orthogonal to the issue. You can have all the problems of JWTs in addition to all the problems of cookies.
The SLJWT does seem useful, but 1h seems too much; if I fear someone might be (for example) accessing my email account using a stolen or hijacked device, they can do plenty of damage in that time. Do you make it clear to the user that their request for a remote sign out might take that long to be applied?
It doesn't have to hit the DB, it could hit memcache or similar caching layer. It also means we could separate this table out from our main DB. We have done neither because it hasn't been an issue (performance-wise) yet.
> Why not just store that UUID by itself?
We could do that, our thought process was that we wanted everything to be a JWT and we liked the ability to, given a JWT, know who it was issued to, when it was issues, and when it expires, all without going to the DB.
> The SLJWT does seem useful, but 1h seems too much; if I fear someone might be (for example) accessing my email account using a stolen or hijacked device, they can do plenty of damage in that time. Do you make it clear to the user that their request for a remote sign out might take that long to be applied?
Totally agree on 1hr being too long and that is why we are planning on lowering it. We have technical reasons (legacy apps that we are trying to get updated) that will not work with lower than 1 hour (I won't bore people here with the details and there are workarounds but we haven't implemented them yet)
Edit: One more point, we also like how JWT's are language agnostic so that we can jump between languages very easily if needed and still use the exact same concepts. Sharing sessions between, say, Java and PHP is not something that is simple/fun/easy to do. JWT's are also easier for us to reason around with, maybe it's just me or my team but I see them as more finite than sessions.