>> You are essentially powerless, and cannot 'kill' a session without building complex (and stateful!) infrastructure to explicitly detect and reject them, defeating the entire point of using stateless JWT tokens to begin with.
> I'm not sure that this is entirely true.
You can be sure it is not true, because it is utter BS. JWTs have an "iat" timestamp field (issued at) and in the described case that an attacker has a leaked token, your validation logic simply should refuse any token with iat < $NOW for that identity.
I have JWTs implemented for a site and in my case, users cannot individually revoke tokens - but they have a "Signout from all devices" option. That will basically just set a field "minimum_issued_at" to $NOW in the database for their user, and any tokens will always be validated against the minimum iat timestamp. That is a good compromise in security and simplicity.
Revocation lists have their purpose, though, in systems with heightened security requirements.
> your validation logic simply should refuse any token with iat < $NOW for that identity.
makes no sense
... ok now it does :) your now is not now, but a stored value
> your validation logic simply should refuse any token before $NOW.
Well, this approach throws out a lot of babies with the bathwater. You invalidate tons of legitimate tokens along with the one that you wanted to invalidate and get a thundering herd [0] of clients wishing to re-authenticate.
This is probably not good in case of a really high load.
And if you don't have a really high load, then there is no good reason not to have a stateful session storage.
[0] https://en.wikipedia.org/wiki/Thundering_herd_problem