However if you need to 'expire' a JWT token early, there isn't a good way to do it. If your token has a JTI, then you could add a blacklist for that JTI (say in redis, with a TTL until the token's exp time). But that is left to the implementor.
My point is, you always have state. If you care about that state being anything but _the current time_ (e.g. just letting tokens expire and not worrying about revocation), you need shared storage.
I see clearly why some small subset of applications benefits from carefully minimizing shared state among components. It is not at all clear to me why pseudo-statelessness is a good default.
The point is that it's easier for distributed systems as a whole when clients hold onto their client-specific state, rather than a minimal token that the server, likely being load balanced for availability, must exchange for that state with yet another service in yet another stateful/authenticated request/response manner.
Isn’t that state? If you add state to something stateless you are generally on your own.
[edit: also I disagree with the notion that something with an expiration date is stateless. It has two states. It’s just that the look like idenpotence]
Why is that scenario relevant if tokens are supposed to be used once per request and short-lived?
Once a token is used, it's supposed to be expired and no longer in use. Both the expiry timestamp and the nonce fields already handle those use cases.
Previous person mentioned logout, so I assumed we were talking about session tokens--which I understand its a misuse of JWTs--and is why he/she's mentioning it.
But if we're talking about just one time auth tokens, then yeah, you don't need expiry ahead of the expiry time, and it's plain it's a non-issue.
I don't agree. The expiration timestamp is not a state, nor is a nonce/token id. Moreover the specs enable servers to arbitrarily reject tokens, which means servers can arbitrarily request token refreshes. This means that any argument regarding how a nonce is a state is entirely irrelevant and without any practical interest.
You've misread what I've said. The server can trigger token refreshes by rejecting the request. According to the JWT workflow, that triggers the client to request a new token and retry the request.
> The question here is which token to reject.
That isn't much of a question, because servers are free to reject any token arbitrarily. They can, however, ignore specific tokens that cease to be valid, such as expired tokens or tokens which have already been used. None of those scenarios involves any change to the token's state.
1) A token gets compromised.
2) You know which token. You need to revoke access.
3) You introduce state by storing said token on disk / in memory somewhere.
Key takeaways:
1) The authentication system (not the token) is now stateful. 2) You now have to check this data store to properly allow authentication. 3) A core benefit of JWT (stateless auth) is gone.
Tokens are single-use and short-lived. Once a token is used it's revoked.
> 2) You know which token. You need to revoke access. > 3) You introduce state by storing said token on disk / in memory somewhere.
You don't. You simply reject the token and let the client refresh its token. That's it. There is no state. Compliant clients already expect tokens to be rejected for no apparent reason. They are access tokens.
Why exactly are you assuming that an access token is not single-use or even short-lived, particularly in bearer token protocols specifically designed so that tokens are ephemeral and single-use?
> 1) The authentication system (not the token) is now stateful.
Even if you shoehorn your definition of statefulness, that's entirely irrelevant. The whole point of an authentication system is, following your line of reasoning, to implement a stateful system. Thus, not only is that line of reasoning absurd, it also completely misses the point of implementing an authentication system, not to mention it ignores a whole class of attacks. And for what, exactly?
Instead of an "active sessions" table you could just maintain a list of revoked sessions and check each incoming request against that list. You can make revocations expire shortly after the JWT was set to expire.
Our implementation requires a number of fields that are optional in the spec.
We don't currently use them for sessions, but I've been planning to. When we do, we'll have a mechanism for invalidating tokens, just like we currently do for our oauth tokens. One way would be to simply embed that in the jwt as a field and check that on each request, just like we do already with oauth. The biggest risk with either oauth or jwt tokens is somebody intercepting them and using them. This risk is about the same for both but it does need consideration.
We are using jwts internally for authorizing messages on our queues and internal API calls. Those jwts have very short ttls and don't leave our infrastructure. They typically include assertions on scope, userids, etc. I've been considering to make JWTs the native format on our queues; i.e. embed the message in the JWT rather than a jwt in the message. This would make message tampering harder for any man in the middle attacks. We already uses nonces in some of our messages so we'd be able to prevent replay attacks this way as well.
The main benefit of using jwts is that verifying them is trivial and can be done without network interaction. Very nice in a microservice type architecture. Jwts are issued on our API server are after verifying the oauth token (not jwt currently). We don't leak these tokens outside our infrastructure currently and we don't have public endpoints that would accept them in any case. None of this is new but not that common in modern REST/graphql type setups nevertheless. JWTs are probably easy enough to retrofit in most APIs that it might be worthwhile exploring this for many.
If you are interested, we open sourced our Java code for creating/verifying JWTs. Check here for an example and more code: https://github.com/Inbot/inbot-utils/blob/master/src/test/ja...
What you're really doing is externalizing your state to one already universally shared, and which we already have a lot of tools to manage: the current time.
Having tokens with an expiry of e.g 10 minutes, but with no ability to revoke, is a totally reasonable trade-off in these circumstances.