To me, JWT works great for things like physical people getting access to a physically isolated building, like a military research site that's disconnected from the internet. Some secure other place holds the private key and signs the JWT token then you can wave in anywhere you need to go until the validity period is up. Then you have to go back to the secure place to get a new key, verifying the same way you did the first time and the secure place can broadcast its public key to the sites you want access to. It's essentially a great mechanism where you don't have constant communication links.
But I just don't get it for servers. Also, everyone considering using a JWT token should know about the "algorithm none" setting and ensure that their stack isn't vulnerable to it.
You only have to involve state in 1 request every 10-15 minutes upon refresh. All other requests can be done without having to check for revocation. This is a pretty nice real-world tradeoff.
Nothing about adopting JWT says you can't still use a full auth check for state-changing endpoints, and use a stateless session to shave some evaluation time off of frequent read-only requests for data that isn't terribly sensitive.
You probably shouldn't do it lightly or prematurely since it makes it harder to reason about authentication, but I think it's worth considering whenever you're optimizing.
A common validity period is around 1 hour, which is good enough that most users won’t need to refresh very many times per day.
Also: you don’t necessarily need to track tokens that aren’t refreshable. A typical architecture might have a timestamp stored per user that specifies the earliest token creation date that’s valid for refresh. That way you can invalidate all tokens without needing to ever store them; something you might need to do for password reset, for example.
Never worked with JWTs but still, can't believe I didn't think of this. It seems like a fairly elegant way to revoke things where your only stored state is a timestamp.
There's a race condition there, though. If you have a revocation event and set the timestamp, it's possible that an in-progress refresh might have a timestamp just slightly after your stored timestamp. Then you have a rogue JWT that can continue to be refreshed.
Clocks are sometimes not in sync with millisecond precision. Databases don't replicate instantly. Distributed systems just don't work that way.
I just read about it on Auth0 [0] and facepalmed. Then I went to node-jsonwebtoken to ensure they added an ‘algorithm’ argument to a ‘verify’ call and you guess what [1].
They added ‘algorithms’, but into ‘options’, so that naive user like me could just skip it and stay open to attacks. That’s auth0’s own module, btw.
Thanks for pointing that out!
[0] https://auth0.com/blog/amp/critical-vulnerabilities-in-json-...
[1] https://www.npmjs.com/package/jsonwebtoken#jwtverifytoken-se...
Hint: you don’t — but I figure taking the Socratic approach may be more convincing.
If you need to do revocation you need to call an external server.
If you need to call an external server why do JWT?
That seems like the charitable interpretation. Note that the author’s point has not been that JWT is useless, but rather that trying to use stateless JWT for sessions is a bad idea.
If the point of using for JWT was to avoid all server side state in authn/authz flow — which is the case for many, many developers, and that is the intended audience of the author’s post — then one of two things: you either contradict yourself and implement server side revocation for refresh tokens, or you let the lifetime of your sessions be the same as the refresh token — and in the case of refresh tokens with no expiry, the user (or anyone with their refresh token) can stay logged in forever.