Thing is, token refresh service can be stateless, but adding a revoke service basically kills JWTs main advantage, since every time we check its validity, we need a query to see if its been revoked.
Thing is, token refresh service can be stateless, but adding a revoke service basically kills JWTs main advantage, since every time we check its validity, we need a query to see if its been revoked.
But since such a revocation list is going to be short (usually 0 entries, dozens at worst), it's trivial to replicate across all the auth service nodes (which can as well be worker nodes) or keep it in Redis replicated per DC, with sub-millisecond lookup times.
Things get harder if you want a feature like logging out other sessions, or just an explicit logout on a shared computer (think about business settings: stores, pharmacies, post offices), you may have to have larger revocation lists. This may still not be a problem: a million tokens is a few dozen megabytes, again, a per-DC replicated Redis cluster would handle it trivially and very cheaply.
I'm of a more gradual opinion regarding this - say you operate a movie streaming service and control access to movies via JWT. It's not a problem if an attacker has access for two more minutes than intended.
If you are talking to a single client, I think checking the remote IP address and encoding it in the token might work to see if the token is not stolen, but don't quote me on that.
I get that this has conceptual appeal, but I doubt this makes any difference in real life. Unless you have some very sophisticated infrastructure, it takes many minutes to discover the issue and then many more minutes even to decide what to do about it. A few extra minutes to cut off access is probably not going to make a big difference one way or another.
When I had a chance to design a token-based authn/authz system, we had two types of tokens, general access (with hours of expiration, mostly read-only access) and privileged access, with expiration time set to a minute or so. All auto-refreshed on use, all separately revokable.
Seems to me that for most applications, the irrevocable 5-minute token seems "good enough".
To revoke a token:
1. issue a new token to the revoker that is issued at current time (if business rules require revoker to be logged in).
2. set user inb to current time - 1 second with a TTL of longest issue * 1.5.
3. Add user to bloom filter.
4. upload bloom filter to s3, every service downloads this every 5 minutes.
5. Then on request, check bloom filter. If the user id is in the bloom filter, check with revocation service that inb > issued time.
This is probably less than five hundred lines of code and pretty easy to maintain.
It also makes e2e testing very easy since you should be logged out after pushing that button.
But yeah, if you have a revoke service, might as well just use session keys.
Edit: typo