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.
> 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.