Live data from Hacker News

Stop Using JWTs

gist.github.com

251–260 of 335 posts

Re: Stop Using JWTs

#251

I'm sorry I fail to see the difference between a cookie holding a server session ID and a cookie holding a JWT token. JWT sessions are created and stored (in some way) in the DB anyway and it's short lived. That's basically a session stored in a DB. When we say no to sessions we only mean server sessions in your backend service as this can't scale horizontally. I feel like this is just a shiny title confusing differe…

Agree, snippet is conflating a lot of things.

JWT is a signed JSON blob.

Cookie is a storage and transport specification.

Local storage is a storage spec.

A "regular" cookie could also be a signed cookie which is basically the same thing as JWT.

Slight disagree in horizontal scalability--server sessions scale somewhat with Redis, replicated DB but obviously not to the degree stateless ones do.

Also on revocability, you don't need to revoke the token if you're validating fine grain permissions outside the token. You can revoke the permissions (ie disable the user). You can use JWT to gate permissions at a high level (infrastructure, traffic edge, API gateway) then validate fine grained permissions in code

Re: Stop Using JWTs

#252
post #3

Necessary qualifier: for browser-based user sessions. Plenty of good uses for JWTs for service-to-service communication. edit: I read some of the linked stuff, e.g. https://paragonie.com/blog/2017/03/jwt-json-web-tokens-is-ba... . Please, if JWTs are such a horrifically insecure standard, go ahead and publish your means for hacking AWS STS's AssumeRoleWithWebIdentity , or don't publish and just exploit it by launchin…

> Necessary qualifier: for browser-based user sessions. > Plenty of good uses for JWTs for service-to-service communication. This is the sensible conclusion right there. I agree JWTs are the wrong tool for the use case of user sessions in the browser. To give some more arguments: All the signature and encryption stuff in JWTs is complex. While common JWT libraries have now mostly got their stuff together, this has no…

Most requests are reads and letting someone use an invalidated session for reads for 30 seconds on a shortlived token isn't the end of the world, especially considering that the exact invalidation timing and its propagation is already somewhat arbitrary.

For rarer privileged actions you can check a token revocation list.

Re: Stop Using JWTs

#253

I'm sorry I fail to see the difference between a cookie holding a server session ID and a cookie holding a JWT token. JWT sessions are created and stored (in some way) in the DB anyway and it's short lived. That's basically a session stored in a DB. When we say no to sessions we only mean server sessions in your backend service as this can't scale horizontally. I feel like this is just a shiny title confusing differe…

JWTs aren't stored in a backend though. Session cookies you exchange an opaque value with the DB for the user info JWTs the user hands you their driver's license, and you can verify that it's an authentic license for the person who's name is on it

The word "session" is overloaded. In browser terminology, a session cookie is one that expires/is cleared when you exit the browser (it doesn't persist on disk)

In application terminology, a session is user state that outlives a single request.

Depending on what definition you use and how pedantic you are, a stateless signed cookie is also a session cookie.

Re: Stop Using JWTs

#254

Security doesn't start or end with JWTs. A user wants to access a read-only resource with an invalid JWT? Envoy bounces it without passing the request through to the backend. Valid JWT? Let the request through without having to look up any session information. No DB, no cache, no session server hit. Fast. A user wants to change a password, email address, or add an authenticator? First, require a password, second, req…

Your database can double as the revocation list. You can use a last modified timestamp on the user or a monotonic counter to determine if a JWT is stale.

Re: Stop Using JWTs

#255
post #189

Earlier quoted context omitted.

So don't do that - and you're stateless! I can't recall the last time I used a "Logout" button anywhere. I no longer visit internet caffees...

Every authentication system i ever implemented (and I worked on many) needed some way to invalidate sessions regardless whether it’s self service for the user or not. And once you do you need some state and then JWTs don’t make much sense anymore. There are of course many valid use cases for JWT so “JWT bad” is a very reductive take

It's curious: very few authentication systems I ever implemented needed some way to invalidate sessions.

Re: Stop Using JWTs

#256

Earlier quoted context omitted.

Revocation lists can simply be replaced with a "tokens not valid before" field per user. When a user logs out, set the field to now(). Reject JWTs that have an iat less than that value. Am I missing something?

What you're missing is that you're still creating state. You're still having to check a database to determine what the "tokens not valid before" value is for that user. And what if the user is logged in from multiple devices, but only wants to log out from ONE of them? Your solution logs them out from all of them. The entire point is that it is not possible to have authentication that is both: 1. stateless. 2. secure…

There is middle ground. Authn can be stateless and authz stateful. Usually it's impractical to shove all the authz nuance into a JWT anyway

Doesn't address logging out a single session, though

Re: Stop Using JWTs

#257

Earlier quoted context omitted.

A JWT is usually signed, with a secret you keep in your app. The statelessness of JWT is that it contains all the information you need to verify it. You do not need to ask a db if the token is there and valid. Storing a user's secret, the same way you store your applications secret does not make it more or less stateless. In since you now have 2 layers of protection, you don't actually need to verify agains a user's…

> [...] you don't actually need to verify agains a user's secret immediately, you simply need to check that the token is valid using the app secret. The subset of valid tokens that you need to check is much smaller than the universe of all the unexpired tokens your application has issued. What you are describing here is different than what is described in the blog post that you linked to. Please look at the definitio…

Maybe I should add a comment there, but this is a compressed example. Everything from getUser onwards does not need to be in the validateToken, it can be done downstream, closer to where you access user data. It does not need to be a separate db call, You pull a user and want to perform an action, so data is in memory, use the secret from there.

Or if you are doing inter service communication, you can use your app secret to validate that the token can actually cross your infra boundary (no user query here), and each internal service can then validate it in their scope, or if a passthrough (like a proxy), just forward it like an envelope.

What this does is give you 2 secure layers, therefore saving you from a lot of the compute (drop expired and globally invalid tokens at the boundary), kill db round trips meant only for token validation (attach to an existing user query you already do) and kill revocation list management.

Re: Stop Using JWTs

#258
post #170

Earlier quoted context omitted.

A JWT is usually signed, with a secret you keep in your app. The statelessness of JWT is that it contains all the information you need to verify it. You do not need to ask a db if the token is there and valid. Storing a user's secret, the same way you store your applications secret does not make it more or less stateless. In since you now have 2 layers of protection, you don't actually need to verify agains a user's…

> Common workarounds like maintaining a blacklist of revoked tokens introduce statefulness, negating the benefits of JWTs. > Validation: On each request, we validate the JWT's signature using the application secret and then validate the sjti using the user's secret. Having to lookup the user secret from the db is no different than consulting a list of revoked tokens. You claim consulting a list of revoked tokens to b…

"which we'd likely do anyway for authorization checks". Assuming you are using a session token, authentication != authorization. You will eventually hit your authorization logic to check if the user can perform action X. It may just be through claims in the token, but I don't think most are doing that. So you will eventually pull user data and you can to this check there if you are passing the token through context.

I have been using this for a while, and I haven't managed a revocation list, I haven't done user queries at the boundary and users are able to logout and instantly invalidate their JWT. I honestly haven't seen this elsewhere without overhead.

Re: Stop Using JWTs

#259

Hmh, the way I usually use JWTs is as an authentication cache. You obtain your authentication token from the auth service which grants you permission to other services. This has several advantages, the main one being that sub-services do not have to interact with the authentication database or have access to the capability to mint tokens (this assumes you use RS256 not HMAC). So if a sub-service gets compromised it's…

At my last work we used to use "the client obtains the authorization token from the auth service, and supplies it to other services" too, but at some point we found that a) permissions in the JWT grew a tad too large to reliably pass them in the HTTP headers; b) localStorage is finicky, as is reliably refreshing it — Safari on MacOS apparently turns off the JS timers if the user looks away from the open page; c) the client can actually see how we represent permissions internally; d) the client only really ever faces a single most popular service anyhow; e) that most popular service used only JWT for authentication as well, so stealing a JWT token was a problem.

So we switched to that main service obtaining the client's JWT itself from the authorization service, and then handling refreshing it on its own. That means that if the client e.g. buys some new feature, they still need to refresh the page (so the new connection to the main service is made) to see it working, but it's always been this way even before, so... eh. We had to scale the auth service a tad, but other than that, it worked fine.

Re: Stop Using JWTs

#260

Earlier quoted context omitted.

> Fair enough, but those optimizations are basically free. People think stateless tokens are free but they really are not. Strawman. The only requirement for a JWT is posting the JSON Web Key set with the public keys used to verify the JWTs signature. That's the full cost of a no-frills JWT implementation of you exclude IAM. If you want to have one-time JWTs you need to maintain a revocation list. This is literally a…

Yes we have heard this before, React is only 30kb! But that misses the enormous amount of infra you need to even just do a basic fetch. (Read the post by the React Query author on whether you need React Query or not) Likewise with JWTs for sessions you need to handle cache invalidation, revocation lists, key rotation, the list of difficult comp sci problems really does go on! The same issue as always plaguing the fro…

> Yes we have heard this before, React is only 30kb!

Not quite. You might be surprised to know, but the whole JOSE standard, and JWT in particular, specify a very limited set of fields. Whenever anyone starts requiring more than that, the responsibilities start to be offloaded to the likes of OpenID Connect.

Post reply on HN