> Just pick a crypto scheme and the JWT is just an encoding that makes it easier to use.
That's not what JWT is, but I can understand why someone would be misled into believing that.
JWT isn't just an encoding format, it also includes a crypto algorithm negotiation protocol that lets the attacker choose the algorithm. Even if you strictly allow-list which algorithm you want to support, you can accidentally bypass this control in many libraries if you support the `kid` (key ID) header. [1]
It also allows attackers to completely strip the security. [2] [3]
Put shortly, JWT is a gun aimed directly at your foot. That's why there's so much hate for JWTs.
Every JWT proponent says that, but it's a misuse that shows up in multiple libraries, in multiple languages, and isn't explicitly called out in the JWT Best Practices RFC at all.
I'm going to blame the standard for being error-prone.
There's nothing in any JWT RFC, to date, that calls out the need for cryptographic keys to be the raw key material in addition to its parameter choices, rather than just the raw key material. That's a fault of the standard.
That's not a single library's fault. That's the standard's fault.
I don't think it's called out in the RFC because when you have a list of all the keys that are accepted, it makes it so the algorithm is effectively whitelisted.
And let's say you've got three different API endpoints, which each hard-code a specific algorithm (one HS256, one PS256, one ES256). But, because of the framework you're developing in, you're expected to provide a single configuration object containing a map of key IDs used by the entire application. (This is a common framework quirk.)
What stops you from swapping out the kid in a JWT's header and getting the underlying library to use the wrong key type for the endpoint that accepts HS256?
The answer varies per implementation. The JWT standards do not call this misuse potential out at all.
Strictly listing the keys does not, at all, hard-code the algorithm those keys are used with in every possible programming language and runtime.
Some languages (Java) accidentally prevent this through type safety in the low-level crypto APIs. Others accidentally prevent this by not supporting the kid header.
I have yet to see a JWT library that deliberately prevents this misuse potential. Is that the library's fault? Or their defaults' fault?
But that's the problem with JWTs, the whole "if you..." part. You want fewer of those rather than more in your crypto code, and JWT has too many. That's the whole problem.
https://www.zofrex.com/blog/2020/10/20/alg-none-jwt-nhs-cont... - where the punchline is "Writing the code to sign data with a private key and verify it with a public key would have been easier to get correct than correctly invoking the JWT library. In fact, the iOS app (which gets this right) doesn’t use a JWT library at all, but manages to verify using a public key in fewer lines of code than the Android app takes to incorrectly use a JWT library!"
Just pick a crypto scheme and the JWT is just an encoding that makes it easier to use.
(It's just a more convenient way of rolling your own scheme)
That said: random tokens have a lot going for them :)