Live data from Hacker News

Stop Using JWTs

gist.github.com

211–220 of 335 posts

Re: Stop Using JWTs

#211

Earlier quoted context omitted.

You can make a JWT invalid after 30 seconds or even 1 second. You should set an aud (audience) when creating the JWT. Otherwise the signature is crypto-graphically sound. Validate every single JWT every single time with a short lifetime. OIDC tokens are all JWTs btw.

The ID token is always a JWT when doing OIDC, and it makes sense in this situation. Because the ID token is not a set of credentials, but signed information you’d use to create/update a user’s profile. You can technically use JWTs as access tokens, as the spec doesn’t specify a format for access tokens, but in my experience they’re normally opaque bearer tokens.

I prefer saml 2.0 for jit provisioning.

Re: Stop Using JWTs

#212
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…

> Please, if JWTs are such a horrifically insecure standard, go ahead and publish your means for hacking AWS STS's AssumeRoleWithWebIdentity

The standard and AWS' specific implementation thereof are two different things. Can you afford a security org the size of Google or Amazon's security orgs? If not, you are playing a different ballgame.

Re: Stop Using JWTs

#213
post #107

Earlier quoted context omitted.

WTF: > Each user has a secret: Stored securely in the database. > Stateless Validation: The core validation remains stateless. We only need to consult the database for the user's secret, which we'd likely do anyway for authorization checks. Is "stateless" the same as "serverless" now? Is author's brain stateless?

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…

Being able to quickly reject invalid sessions identifiers is a useful property in some cases and is normally done by authenticating stateful session tokens with a MAC using a global app key. This can be used for DoS protection if the cost of a database lookup is more than the cost of MAC, and the complexity is justified. It ensures that the random numbers a user is trying to present as their session token are the numbers generated by the server if the key is not leaked.

Because you're trying to bolt things on top of JWT, you're creating a worse version of that stateful authentication pattern:

1. You lost the statelessness of JWT by making database queries. Your claim that "you don't need to verify against user's secret immediately" is false, as you need to do that in all cases immediately after verifying the JWT signature to get the benefits of your system (token invalidation). Sure, you reject completely invalid tokens early, but you still need the statefulness to authenticate users properly (if your goal is to be able to invalidate tokens).

2. In your version, getting a read-only access to the user database (leaking per-user secrets) completely destroys token invalidation, and all your authentication now depends on one key. If, in addition to that, the JWT signing key leaks, user authentication is completely destroyed and can be bypassed by the attacker, who now can sign in as any user. (A common way to leak all this is by failing to properly secure backups).

Compared to a stateful session system with split-tokens, where the database stores tokenId => verifier, where verifier is Hash(randomToken), and user's token is id||randomToken, read-only access to the database doesn't let the attacker authenticate as any user. If the tokens that users presents are in the form of id||randomToken||HMAC(serverKey, id||randomToken) for early rejection as above, leaking serverKey still won't allow the attacker to authenticate as any user. The attacker needs write access.

> Is author's brain stateless -- my bad, I thought this was not reddit

I didn't realize that you were the author, I thought you were a reader who was misled by this blog post. Even better: you can go and edit it, removing "stateless" everywhere! It's fun to invent various protocols, but when someone points out the errors, surely you'd want to fix them -- no shame in making mistakes if you correct them.

Usually, when I think of a protocol, after writing down "Benefits" (as in your blog post), I write "Drawbacks" and then try to come up with downsides and compare it with existing protocols. I'd suggest you do the same.

PS. Find yourself in this picture: http://cryto.net/%7Ejoepie91/blog/2016/06/19/stop-using-jwt-...

Re: Stop Using JWTs

#214

This links to some other blog post for the bulk of it's 'why', and that blog post mostly seems to be annoyed about "You cannot invalidate individual JWT tokens". Which every time I've implemented, the general guideline is to check for invalidated nonces somewhere. Which resolves that random blog posts second point too. >The JWT specification itself is not trusted by security experts. This feels like it needs more evi…

Right, but once you're checking for invalid nonces, your token format is now stateful; it's lost the primary benefit of statelessness, which is continuing to function under network partition between the application server and the token state store.

How can you provide a stateless logout (that invalidates credentials rather than simply forgetting them client side)?

Re: Stop Using JWTs

#215
post #181

Earlier quoted context omitted.

If you have multiple services in multiple locations however, you may want to replicate this data, so in this case revocation list as it's much smaller would be far easier to replicate for much less latency overhead.

Then you have to replicate all the other data too? I don’t see the issue.

That is not automatically given in any system and depends on the system. Authentication, however, is a minimum required feature in most system that would introduce latency. Just imagine sending each and every http request from a user half way round the world to lookup the session - latency would be terrible.

Re: Stop Using JWTs

#216
I think people were using them to skip hitting the database for an auth check on every request, but revocation is hard, e.g. someone quits, but nothing on the backend of their old company's services is checking their JWTs stored in their browser, so they still have all the access they ever did.

Re: Stop Using JWTs

#217
JWTs are awesome but they are are being overused by people. People use them in web, on mobile and everywhere in between. Places where cookie or bearer token auth has already solved the problems. JWTs strength is that it can be verified independently without real-time coordination between services. So a service can issue a JWT with auth scopes to a user. The user can take the JWT to any other service and if that service trusts the signer, it'll allow the user access and also get basic user info from the token itself. The service doesn't need to make an API call to the issuing service or even know if/where it exists. That is where JWT is really powerful.

For web/mobile auth where same server issues the JWT and same server verifies it, it makes no sense. JWTs cannot be invalidated. If a user loses some permission or account gets disabled, JWT will still be valid until its expiration time. Servers must either make DB calls to verify the user is still active or be fine with deactivated users having access for a while after account is disabled. This completely defeats the purpose and bearer tokens work perfectly for this use case.

JWTs should _almost_ never be used in client side auth. Client should send regular cookies and bearer tokens. The auth server can internally generate a short lived JWT and inject it into requests before they get routed to various services internally so those services don't need to query DB every time to verify the user.

Re: Stop Using JWTs

#218
post #9

JWTs are insecure... even when using trusted, rsa/ppk based signing methods? not shared secrets. JWTs are too long lived... Nothing is stopping you from limiting the JWT lifetime and having a refresh model against an authentication authority... I mean, even if you use cookie based sessions, you're storing somewhere... you can have a jwt valid for 5-15min. 15minutes is roughly the cache timing for many authorization s…

They aren't insecure really. They're pretty secure by design but people are using them for things they were never designed for like web/mobile client auth.

Re: Stop Using JWTs

#219
post #46

In sessions vs. JWT revocation lists, there is an argument in favor of JWT revocation lists. JWTs have a limited expiry timestamp, so you only ever need to maintain a revocation list for tokens not expired yet. Given that you probably only have a fraction of JWTs revoked compare to valid JWTs in circulation, you only need to query a very small dataset for each request. When using sessions, your list of valid sessions…

The moment you have to look up the user object, you've lost the primary advantage of JWT, and might as well ditch it.

This. Totally defeats the purpose of having JWTs if you have to hit the DB or some service to validate the token every time.

Re: Stop Using JWTs

#220
post #13
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…

JWT used to be bad due to libraries with poor defaults. Downgrade attacks were fairly common a number of years ago. Since most of the common libraries across all languages have gotten more sane defaults, it actually is pretty secure nowadays.

JWT libraries had poor defaults because the spec was poorly designed.

Of course JWT can be implemented securely. Even XMLDSig can be implemented securely. But if the spec is not designed with security and misuse-resistance as a tier 1 priority, you will get more issues. The fact that we didn't see the same sheer volume of issues with PASETO or macaroon libraries (admittedly, the later are far less numerous). I can find only one CVE for a PASETO library from 2020, and this is an issue that has nothing to do with the algorithm itself (JPaseto The reason PASETO won't have the same issues as JWT is the design (especially with v3/v4). There is no alg=none, symmetric keys are fixed size (so no weak keys can be used) and algorithm confusion is prevented by an explicit implementation guide[1] that strongly mandates that keys for different algorithm version have different types, and verification functions MUST reject a key of the wrong type.

Is JWT safe now? Maybe. A lot of issues have been fixed, but new issues keep coming all the time. We're not even halfway into this year and I can count at least the following serious 2026 CVEs: CVE-2026-28802, CVE-2026-29000, CVE-2026-1529, CVE-2026-22817/8, CVE-2026-34950, CVE-2026-23993, CVE-2026-32597, just to name a few. Most of them are the same classic alg=none, signature verification bypass and algorithm confusion issues.

The issues is that new libraries are coming all the time and the vulnerability elimination process for existing libraries is just a random scattershot. If a security researcher has happened across a vulnerability in library X and reported it, it's solved. If nobody has found it yet: though luck. Unless you pick a library that has been officially audited for these issues, you don't really know if it's truly safe. If you use a PASETO library, it's probably not audited either, but the chance of it having these common types of issues (and other issues, like psychic signatures[2]) are close to nil.

---

[1] https://github.com/paseto-standard/paseto-spec/blob/master/d...

[2] https://www.securecodewarrior.com/article/psychic-signatures

Post reply on HN