So, should I think that you agree with the article?
The point is not to be stateless for its own sake, but to leverage less state in a way that's beneficial (e.g. not having to authenticate every request). If adding back a little bit of state in a different way mitigates the major downsides, that can still be useful if it doesn't entirely negate the benefits already gained.
The article has a perfectly nice point, that nearly every site does not need stateless sessions. Keeping them on the database is perfectly fine.
The article also has a point that there it is impossible to revoke certificates without shared state.
People here have a point in that it is possible to optimize that shared state as much as it is a performance non-problem.
Other people here have a point in that this is a hard problem that isn't solved by default, so you either do some low level work creating your revocation list from basically the ground up, or you'll get something that is worse than a database.
Yet other people have a point in that it's hard to set your PKI correctly and if you don't want to bother with that, you are better with a standard database implementation.
All of those are true.
Of course, this gets to the point of the article -- if you're loading data serverside, that's not reeeaaallly the intended multi-party-claim-exchange use case of JWT's....
> every time someone changes their password—which should certainly invalidate their old tokens
Using a variation of above, you can just reverify the JWT every X minutes, and know that if you change a password for normal reasons all JWT tokens will be invalidated within X minutes.
It's a trade off. If you can live with what you're trading (or at least live with it after mitigations are put in place), it might be worth it.
The reason for using JWT is that the UI and backend consume the same session object seamlessly. Before what we got in our PHP session and what state we shared with the UI were manually kept in sync through a API request.
what fields are in this session object besides an identifier?
But, what are you getting for this added complexity--above and beyond what "traditional" user session management provides?
Of course, if the DB concern is one of performance, then there's also a performance trade-off with JWT since the (sometimes large) token is constantly transferred over the wire and compute is used to decrypt it. That may be faster than a DB-round trip, but it's not free. Of course, "old-school" session-management keeps the auth state in memory server-side, which can be the fastest--though comes with a memory hit. But, constantly processing the token in-memory also assigns a memory penalty (even if slightly more transient).
In any case, I think it's like a lot of popular tech that evokes strong reactions on both sides: The success of the tech causes it to be overused, invariably in use-cases for which it isn't as well-suited or was not originally designed.
In this case, the important need for session expiration alone makes me question hard whether JWT is a good fit for session management in a lot of user-facing apps. In some cases it will be, but in others, there are probably better solutions.
There are cases where JWT can make a lot of sense. For example, a high capacity API where you don't necessarily want to check auth for every request, especially if you can rely on some sort of caching infrastructure. In that case it may make sense to use JWT, re-check the authentication on some set schedule (whether once an hour or day), and save yourself what might be a few thousand authentications a minute.
With the advent of SPAs and RESTful designs, it was probably tempting to say, "hey, let's allow our user-facing client apps to hit the API directly and use the same JWT token scheme for auth there". So, whereas it was generally a good scheme for APIs, it became a YMMV thing once it diverged into the client.
I'mnot sure that's entirely true. It's not hard to include an extra static token within the JWT which is delivered to the servers through an alternative method (pushed with production, or manually set), which when it changes forces a re-auth (either just a DB auth session because you've specifically set the conditions such that you only care if PW changed or some other flag set, or a full login procedure).
If the same static token is used for all users, all users will need to do this on the next request. If you subdivide your users by some metric (first x characters of username, some modulo of numeric ID) then you can invalidate some subset of the userbase JWT tokens instead.
You've now gained the ability to immediately invalidate a JWT tokens as long as you're okay with forcing extra computation on some larger set of completely valid ones at the same time.
Edit: Changed wording of last sentence to clarify you don't necessarily have to invalidate all sessions just by invalidating all JWT tokens, as outlined in further comments below.