- to revoke a JWT you have to blacklist it in the database so it still requires a database call to check if it's valid.
- JWT are to prevent database calls but a regular request will still hit the database anyway.
- JWT are very large payloads passed around in every request taking up more bandwidth.
- If user is banned or becomes restricted then it still requires database calls to check the state of user.
- JWT spends CPU cycles verifying signature on every request.
- JWTs just aren't good as session tokens which is how a lot of web developers try to use them as. Use a session ID instead.
Where JWT works best:
- when a client can interact with multiple services and each service doesn't need to do a network request to verify (ie federated protocols like OpenID). The client verifies the user's identity via the 3rd party.
- as a 1 time use token that's short lived, such as for downloading files where user gets a token requested from auth server and then sends it to the download server.
Once you go down the path of checking a DB along side the JWT your design has gone off the rails. Either the expiry works for you or it doesn't. Don't try to "fix" it.
The blacklist is smaller than storing every token and not needed if you use a short expiration and refresh often.
> JWT are to prevent database calls but a regular request will still hit the database anyway.
It's one less query per request plus not all requests need the database immediately.
> JWT are very large payloads passed around in every request taking up more bandwidth.
They are 100~ bytes instead of 10~, not "very large".
> If user is banned or becomes restricted then it still requires database calls to check the state of user.
This is the blacklist you mentioned as the first reason.
> JWT spends CPU cycles verifying signature on every request
Pretty sure this is neglible. Similar to SSL requests.
> JWTs just aren't good for authentication which is how a lot of web developers try to use them as. Use a session ID instead.
Opinion. I weighed the pros and cons and JWTs are still worth it for my authentication use cases.
For the size argument, you can use cbor instead of json. (CBOR Web Token) CWT https://tools.ietf.org/html/rfc8392
But this video says all I have to say (2018):
https://www.youtube.com/watch?v=JdGOb7AxUo0
1 sec takeaway (More in the video):
https://i.imgur.com/vUYTYfS.png
That said, JWT's are great for stuff like 2-Factor via email link or redirecting from one domain to another. Single use, which it was built for.
JWT was meant to be stateless, if it's not, then it's just a layer of unnecessary complexity with potential security and implementation flaws.
Basically a bunch of endpoints can be put up, and if they use JWTs, it is easy to hit those endpoints from any type of app.
Cookies can of course be used, but that requires pulling cookie jars into native code. Perfectly do-able, but also super awkward and potentially error prone. e.g. I remember using apps on Windows that required me to clear my Internet Explorer cookies if the native app's auth got into a broken state!
(Things aren't that bad anymore)
JWTs are also nice because I can easily write services that authenticate to each other. I can have a service running on my backend that authenticates its limited access service account, gets a JWT, and goes and talks to another service. Could I pass around cookies? Sure, but it'd be more work and more complicated than "attach this JSON blob".
Cookies are nice if everything is browser based, but I'd argue that isn't the best way to build services.
(And finally, the amount of time I've spent debugging JWT issues < the amount of time I've spent debugging cookie issues!)
Reference:
[1]: https://zaiste.net/creating-secure-rest-api-nodejs-without-j...
Our API knows that that organization's auth server is allowed to sign tokens, the third party frontends can obtain those tokens and send them to our API, and it works (or so I hope, I'm in the reading up on all this stuff phase). Sessions using regular cookies just don't.
It was easily implmeneted, easy to understand, secure by design and not open to any of those security issues because there was no magic lib which would have allowed for some downgrade attack.
And what did it actually solve? Session stickyness. Simple and easy.
Everything else isn’t JWT. Sure you can use it with OpenID/OAuth/whatever. Sure you can store them in cookies. Sure you can use them with or without sessions. But how is any of that related to JWT specifically?
One of the articles says with JWT I have to re-implement session management. Just use a different framework then. Sessions with cookies are also not magic.
Another article basically says you don’t need OAuth 2.0 with access tokens and refresh tokens. Very true. Also not about JWT.
I recon if the library you're using doesn't force you to pin the algorithm (or opt out of pinning), your foot is probably already full of bullet holes.
I'm also not a fan of "sessions" other than at the client, they tend to fail at scale.
RSA or ECDSA with NIST curves for signing things doesn't strike me as "great".
tptacek
Credential attenuation in Macaroons is
cryptographic; it's in how the tokens
are constructed. I don't see the opportunity
for a DoS (that didn't exist without
attenuation already).
Macaroons are a really lovely, tight,
purpose-built design that happens to
capture a lot of things you want out of
an API token, including some things that
JWTs don't express naturally despite
their kitchen-sink design.
JWT is more popular because there are
libraries for it in every language, and
people don't think of tokens as a cryptographic
design (or nobody would be using JWT!), they
think of them as a library ecosystem. JWT
is definitely the stronger library ecosystem!
This is also why I probably wouldn't ever
bother recommending PASETO. If you're sophisticated
enough to evaluate token formats based on their
intrinsic design, then you should implement
Macaroons if possible (it's almost always possible).
If you're not, then you're going to use JWT.Macaroons have many small edge cases that'll bite you when you try to use them in practice:
- there is no spec and all people re-implement the de-facto standard. If you read the whitepaper it's not what's in use.
- the de-facto implementation is full of holes, e.g. time is expressed without timezone so it's not clear if it's UTC or not.
- the implementation requires custom parser for custom binary format but the caveats in wild use (remember: there are no standard ones) still use text so it just avoids the potential benefits of encoding dates and numbers in binary.
- the highly hyped third-party macaroons are barely supported in implementations in the wild - only one level is allowed and it's not specified anywhere.
- if we're talking about third-party macaroons there is another layer of problems: no standard for caveats means your third-party service needs to be closely coupled with your own.
- immature implementations, I'll just leave this here: https://github.com/nitram509/macaroons.js/blob/master/src/ma...
JWTs have many problems but compared to Macaroons it's just JSON and base64. This is available in all programming languages with no additional cost. JWTs also have actual spec that implementations can agree on. Macaroons promise you extreme power but doesn't deliver. Several of Macaroons issues could be resolved with some effort (e.g. standarization) others - like resolving cycles in third-party caveats are IMO design flaws deeply embedded in the format.
For more info from people deploying Macaroons in the wild see https://www.youtube.com/watch?v=MZFv62qz8RU
As for tptacek's recommendation this only serves as a reminder that even if a highly respected internet figure recommends you something you still need to do your own homework instead of blindly following.
Wow. In case the master changes, here’s the highlighted code:
/* XXX get some random bytes instead */
var enc_plaintext:Buffer = new Buffer(MacaroonsConstants.MACAROON_HASH_BYTES);
enc_plaintext.fill(0);
This library’s README should have an all cap “toy project, don’t use” up top.But we are not on the same page about Macaroons and what makes them interesting. I do not care about interoperability and standardization (I do sometimes, but not here). Apart from things like OIDC, most of the JWT usage I see is internal to projects; they're used as a utility library to do utility crypto in HTTP APIs. In those scenarios, it doesn't matter whether "your" Macaroons are the same as mine.
What's interesting about Macaroons are the underlying design.
I'm honestly surprised to hear that anyone would go into a project with something like Macaroons and expect to fit into a pre-existing ecosystem of compatible Macaroon implementations, because, as the post says, they're not widely used.
I note that the logo depicts macarons [1], rather than macaroons [2].
A parent comment also mentions PASETO:
Sadly, a paseto does not appear to be any kind of biscuit.
The PASETO site links to this searing indictment of JWTs and related things:
https://paragonie.com/blog/2017/03/jwt-json-web-tokens-is-ba...
I am far from qualified to evaluate any of these!
PASETO is by Paragon, the authors of said searing indictment.
IMHO their argument really comes down to a difference in opinion in how cryptography should be supplied to developers. TLS and JWT standards allow for a wide variety of cryptographic algorithms, and implementations may provide various ways to negotiate that set of algorithms, such as whitelisted set.
This provides for migration over time from legacy systems to new algorithms, but creates a risk that the library author will have a security issue in their implementation of the standard, or that the application developer will misconfigure said implementation.
The alternative strategy is something like NaCL/libsodium http://nacl.cr.yp.to, where experts standardize on single packages of algorithms (or extremely limited set, such as one standard and one legacy) to implement specific cryptographic primitives.
The problem usually quoted here is one of compatibility, migration, and experimentation. There are often no provisions for older systems which cannot handle one of the profiles involved, or primitives for managing non-standard cryptographic sets. Many of these specifications also dictate removal of an old algorithm set to add a new one - making the specification only really valid in lock-step upgraded systems.
Partly (largely?) my fault. When we wrote the Macaroons paper, I was simply not aware that Americans use the French word when referring to the French variety of macaroons.
I think pedantry in auth should be celebrated.
1. Tokens are typically stored in localStorage. (app becomes vulnerable to CSRF & XSS attacks).
2. Tokens can be stolen. Now this is generally controlled by having a very short expiration time.
3. Short expiration times mean persisting refresh tokens to do a silent refresh.
4. Blacklisting of tokens adds complexity and defeats the purpose of decentralising the auth workflow.
5. There's technically no logout. It's all done via very short expiration times. With multiple tabs open, logging out on one tab needs to be synced with rest of the tabs via some event listeners.
6. SSR rendered pages need to send along the latest refresh token cookie so that the browser can use it.
7. The refresh token is sent by the auth server to the client as an HttpOnly cookie to prevent XSS/CSRF.
My colleagues wrote a detailed guide which goes through these considerations - https://hasura.io/blog/best-practices-of-using-jwt-with-grap...
that's a problem with every site in general, which doesn't use any kind of event listeners.
2. Same for any authentication header or token
3. I'm not sure I see the problem
4. See 3, don't do it, use shorter lived tokens with a refresh if necessary.
5, see 4
6. Again, you could still use cookies, and longer lived, or state/revokation backed store... I don't do many SSR in practice, mostly PWA
7. That is absolutely an option... usually, I forward back with the token on the hash, then the first thing the app does is use the history api to pull it out and remove it from visibility... it does appear for a brief moment, but like anything else, you'd see it in devtools anyway.
Unless you have some form of fingerprinting the client who authenticated and received the JWT.
Here's some trivia, the name comes from an italian drink from the 19th century named Fernet-Branca [3].
[0] - https://github.com/fernet/spec/blob/master/Spec.md
[1] - https://branca.io
[2] - https://github.com/paragonie/paseto/tree/master/docs/01-Prot...
https://www.diffordsguide.com/cocktails/recipe/930/hanky-pan...
Anyone here got experience using Paseto in anger? (besides CiPHPerCoder who made it)
I would love a JWT-like thing that's equally common yet better designed. But especially when using it in public APIs and the likes, acceptance has to be pretty broad. Anyone got insights as to how mainstream Paseto is getting?
Okta's a pretty big name in authn/authz and their engineers recently published an open source PASETO implementation.
https://developer.okta.com/blog/2019/10/17/a-thorough-introd...
JWT has been out there for a few years and there are many uses of it that are fine. I've used it in the past and it was easy set up and get started with. The main criticism seems to be that users have too much wiggle room to do silly things like using alg=noneor that certain widely used algorithm combinations have some weaknesses. I guess that's valid but not a huge concern if you know what you are doing.
Paseto looks like it improves by narrowing down the choices to some sane choices, which is a valid approach. Of course IETF could update the relevant RFCs to use the same algorithms for JWT at some point.
>> JSON Web Tokens are Often Misused
So is everything else. Name one programming concept which isn't often misused.
>> There were two ways to attack a standards-compliant JWS library to achieve trivial token forgery
The keyword here is "were" - Just like how people in Europe "were" dying from the Bubonic plague - It doesn't mean that Europe is unsafe today.
The up-to-date reality is that JWT today has been battle-tested to an extent that few other web standards have. In a way, all the negative attention due to past issues has made it stronger.
>> JSON Web Encryption is a Foot-Gun... this is somewhat like pointing a gun with 5 out of 6 loaded chambers directly at your foot
...And using session IDs inside a cookie is like eating a cookie laced with cyanide.
* Why wrote your own format when JWT already has predefined keys. If you write your own encoding format instead of crappy JWT interoperability you have none and have to write everything from scratch
* If you're following API first using cookies for machine to machine API interactions is ridiculous (cookies are for browsers and humans)
* JWT being fairly standard plays nice with load balancer a/auth proxies/API gateways which can off load auth or even route it before hitting the application (database calls are expensive compared to in memory cached auth and you probably have an LB anyway)
I do agree that if you need the particular way of doing authentication that JWT is designed for, JWT is indeed a great implementation and can save you a lot of time.
Iterating on how invalidation work with OpenID Connect when in a point before the author said an authentication service which can go down is a single point of failure you should avoid. So he added a spof by using openid connect...
Anyway, there is always a single point of failure somewhere. There's got to be something that authenticates users and creates tokens in the first place.
Where JWT shines is when the auth service does not need to know the clients that might want to authenticate using it. A system where it can issue tokens to any other service on behalf of a user and say, "here you go, you can use this for the next N minutes". This is very useful when it's not practical for every service/client to "register" itself with the auth service before hand like oauth.
This is absurd -- the total amount of data I needed to store in the JWT was about 10 bytes.
This inefficiency bloats requests. At a time when we're migrating to http/2, which which deliberately reduces headers to speed things up, JWT is going in the other direction.
I've found that arbitrarily re-inventing the wheel because a new thing becomes popular should be done deliberately and with great caution. More generally - I think it's important to look for solutions to fit a specific problem, not problems to fit a specific solution.
However, back to JWTs - I'm currently using them for authorization in an EXTREMELY high traffic websocket server implementation. It's really nice because it's short duration (the ones I am issuing have a expiration of 60 seconds), and allows the service to operate entirely within memory except for interacting with a Kafka cluster.
Consider that host clocks are not always in sync (even NTP could leave 10 seconds of difference) and the many authentication redirections can take quite a bit of time for slow clients. Limiting tokens to 30 or even 60 seconds is asking for troubles.
But then again, I have to work with thousands of hosts, applications and datacenters, so I feel every edge cases. A single application on a single host would not.
I mostly use them in IOT voice enabled devices that get their time limited authorization to access popular voice services through such a token. Voice enabled devices suck, but that is not the fault of JWT. I think without JWT being that common already, we wouldn't have a situation where a devices need to sign requests against voice services and we would have additional security concerns.
It is a given that you can use a complete different token or other cookie mechanisms that work just as well. But I like them to provide at least some common ground. Even if there is valid criticism about the implementation.
Authentication != authorization should always be mentioned on the topic of JWT. And yes, they are often abused to do things beyond their intended scope. I would think this to be a user error.
And then you still have to use JWTs correctly which is very easy to screw up. OIDC has improved this situation somewhat, at the cost of another layer of even more complexity that’s easy to screw up.
Then you come to realize that JWT is basically pointless except for doing MFA (which you could probably have done with a random token).
cause issues down the lime.
"lime" is a typo, should be "line"sign in on www.example.com -> click visit www.example2.com while being logged onto accout based on example
That being said. Please do NOT use basic auth for anything in 2020. This is the worst anti-pattern one could do for authentication.
Basic auth simply transmits the username and passwords in clear text with every request. No application should be receiving username and password in clear text besides a single auth service. The passwords will get leaked all over the place between developers debugging, verbose logs, exceptions, etc... And unlike tokens that are meaningless and expire, textual passwords last forever and are extensively re-used by user across websites.
I guess my basic heuristic is that it's decent for an API that you expect to have very few consumers (internal, partnerships), but I would hesitate to recommend them for an API aiming for wide adoption.
Yes, but I see a lot of implementations where the token is sent to JavaScript and is stored there.
It's best to store it as secure cookie (HttpOnly) so JavaScript cannot access it.