Revocation is essentially the Achilles heel of JWTs - you want to have completely stateless bearer tokens, but if you need to check for revocations, it means you have to do some sort of lookup against a revocation table, and at that point you really lose the stateless nature that you wanted in the first place. There are some tricks to make this more tenable, but it's still a big reason why some folks say "don't use JWTs for end-user auth".
Would greatly appreciate details on how Biscuit implements this with their "revocation IDs".
Edit: Nevermind, I found it: https://www.biscuitsec.org/docs/why-biscuit/ - and it turns out revocation is a "non goal". And then in the linked page about how to implement revocations, they basically do exactly what I do for JWTs: have a revocation list, but then revocations can fall off that list once they're past the expiration date anyway.
So, not to be too harsh, but why would I use this over JWTs? There is no "magic" getting around the "well, they're kinda stateless" problem. To be honest I don't really care about some of the other tangential benefits (after all, you can stick whatever you want on a JWT and interpret it however you like) if it still has by far the same glaring pain point associated with any bearer token system.