The main use cases for JWT are:
* I want to create a session token that I _never_ want to revalidate against a database, and still trust that the only way it can exist is if a user has logged in at some point. This means that you're not going to be and to log a user out of your system, but that can be a valid trade-off in some situations (e.g. low-security applications where the cost of storage is very high, or microservice architectures where the token can be validated on ingress but doesn't need to be revalidated later).
* I want to include role (or other) information directly in the token for the sake of convenience, so I never need to pull information from other sources (in which case there are definitely other ways to do this, but just using a JWT library and using the result as a session token might be easier than the alternatives).
But most cases of using JWT tokens that I've seen has basically involved using them as overly complicated session tokens with all the same problems, and none of the benefits that JWT itself can bring. In that case, you may as well just take the easier option in the first place.
There's the middle ground as well with a long lived authentication or refresh token and a short lived authorization token.
> I want to include role (or other) information directly in the token for the sake of convenience
Once I started seriously developing cloud solutions, this became indispensable. It's not just convenient, it directly reduces expenses.
JWT tokens definitely have their place, I don't want to imply that they're useless. They're a tool with tradeoffs like every other tool we use. But I've seen a lot of projects using them without understanding those tradeoffs, and then creating either very inefficient, overly complex, or subtly insecure applications as a result.
This works up until a certain point. Once you get past simple RBAC to more fine-grained (resource-based) authz, jwts don't scale: https://medium.com/building-carta/authz-cartas-highly-scalab...