What solution would you choose today for stateless auth tokens?
2018: https://news.ycombinator.com/item?id=18353874
https://news.ycombinator.com/item?id=16517412
2017: https://news.ycombinator.com/item?id=14290114
https://news.ycombinator.com/item?id=13865459
2016: https://news.ycombinator.com/item?id=11929267
https://news.ycombinator.com/item?id=11895440
In more words, if you need to carry application state and you haven't outgrown the simple database cluster, then just use the tried and true formula of carrying state via SQL database. Pretty much every engineer these days understands how the architecture works, it's fast and reliable due to the sheer maturity of the components involved, and you don't add cryptography and maliciously crafted input attack surfaces to your auth system (see the recent talk at BlackHat 2019 about Outlook accepting unverified auth tokens). In this case using a predictable and mature approach is a good thing.
On the other hand, JWT's work well for (1) federated authentication, though revocation is still hard, and (2) carrying authorization claims. The reason is that these aren't state in the sense of application state. They're attestations of an existing fact and you're using the signature mechanism to let one service trust another without having to talk directly to each other or to protect any shared secrets. You need to send signed payloads containing user ID's and lists of claims anyway, and JWT's meet those requirements pretty well.
http://cryto.net/~joepie91/blog/2016/06/19/stop-using-jwt-fo...
The problem with JWTs is that they are discouraged by many cryptographers due to their "cryptographic agility" and provide a mixture of protocols which includes weak ciphers and configurations to shoot the programmer in the foot. Why include insecure ciphers in the first place? The mentioned alternatives stick to a single cipher for its intended purpose.
JWTs are inefficient for performance and are bloated in their data structure and have a performance hit when you parse the token to extract its properties compared with the same operation in other alternatives (simple session cookie require zero parsing and thus is faster).
And using them for sessions poses it own pitfalls [2] which you are better off with the alternatives or plain old session cookies.
They say that JWTs are "good when used right" but with those above footguns, that's like saying C++ is safe when used right, rather than having safe defaults.
[2] http://cryto.net/~joepie91/blog/2016/06/19/stop-using-jwt-fo...
In the few deployments I've seen, you end up observing this pattern of, first, not enough information is placed in the JWT to eliminate stupidly common database calls on every request (example: "the JWT contains a UserId, but we need a RoleId that we store on the user document to determine their authorization level. for, like, every API call.")
Ok. So, two options: you can give up, admit JWTs were a weird choice, and just do everything possible to make those common database calls fast (which is a very solvable and scalable problem); or, you can go down the rabbit hole. Lets put a RoleID in the JWT. But, really, a RoleID doesn't tell us anything about the user's authz; it saves us one table join, but we need the underlying permissions/claims/authorizations/etc. We could put those in there.
In other words, "stateless" is a misnomer. You just moved the state; from a single, consistent, and scalable database, to a "distributed database" where every node is a JWT held by your users.
JWTs are probably fine. I just think the most claimed benefit they offer is mostly overblown. But, in the 2% of use-cases where that benefit could be exploited to the maximum, they're worth using, and they're also "fine" in the 98% of other use-cases.
> What solution would you choose today for stateless auth tokens?
Issue token (=random 256 bit string), verify against cached database. If you believe this to be a significant performance issue, you are very likely wrong.
Some use cases:
1) Sign In with Google gives your browser a time-limited JWT that it then provides to the application you're trying to sign in to. The application's server checks the validity of the token (without having to contact Google, except for daily key refreshes) and can upgrade that to a session for your browser using its normal session-management machinery. The idea is to transfer a piece of information between two systems (Google and the server app) through an untrusted system (your browser). For that, the JWT works well enough.
2) I wrote a proxy to convert one's external SSO session cookie to a JWT internally. That ways apps can check the user without having to make any requests to a user service, and can propagate that safely to other backends. It was very time-limited (min(RPC deadline, global deadline) + a few seconds of slop in both directions) and never exposed outside of an internal network.
Some anti-patterns:
You don't want to store sessions in a database, so you store the state in a JWT that the user stores in their browser cache. This has the problem that you can't revoke the token when the user is fired or gets hacked, which is a big problem. (You can of course add a database that only stores revocations... but you now have that check inside your request path, so you should have just done it the other way around and saved the user from having to send you a giant cookie on every request.)
But more importantly, why do you need stateless auth tokens?
I kept the token expiry to an hour or two depending upon the usecase.
Added logic to client to refresh the token right before expiry of existing token. Otherwise, on token expiry, server returns 401 and client can attempt to refresh token or send user to login page.
If there is a need of instant revocation, then I can maintain a list of revoked tokens for the duration of token life (1-2 hours) in cache layer. After 1-2 hours token will be expired anyway.
Everyone thinks they're building the next Facebook, but most of us aren't gonna stress out even a single Redis instance.
IMHO, the problems with JWT are overblown. Yes, people have made huge mistakes implementing JWTs, but the fault lies with the implementation not the standard.
Stateless authentication tokens are always going to problems with revocation. There is always going to be a limit on how much you can cram into them. These problems are not unique to JWTs.
JWT has the advantage of being a standard with good support across languages. Other schemes might be slightly better at handling larger amounts of session data. Take your pick.
I have mostly stuck to plain old server side sessions that are easy to revoke. If anyone is using Go, I highly recommend this library :
There isn't really such a thing as stateless auth tokens. For authentication you need revocation. For authorization, you can't stick that in a token that you send out because permissions can change. So you end up having state that you distribute everywhere anyway, so do it in the easiest way possible. Scaling fast lookups of a session key is much simpler problem.
I use simple http only cookies with the following setup:
"cookie_name=cookie_value; Domain=sub.domain.com; Path=/; Secure; HttpOnly; SameSite=Strict; Max-Age=31557600"
This is valid for a year when you can decide if you want to renew it. Everything else stays on our end and we controll sessions, permissions, etc. Javascript (in theory) cannot access these cookies.
Otherwise, blacklisting tokens as a way of revocation process seems just fine to me. Set reasonable expiration to the key, allow users to refresh keys, then when you need to revoke a key, add it to blacklist together with the expiration timestamp and expire it out of the blacklist at the same time the key itself would expire. You can do all of this by magic by using Redis for your blacklist storage and setting expiration on your blacklisted keys. Yes, you would need to check your blacklist on every request, but a) blacklist is going to be smaller than a list of every issued token (like you would with normal sessions) b) you don't even have to store the whole token, just calculate some hash and store that, now you only need to read a few bytes on every request instead of reading the whole session.
The author does make a some good points though.
Since you need to keep a list of invalid tokens, it's not easier to just use standard token. If what's you like in JWT is the ability to store a payload that your backend gets back, you can keep that in your store alongside the token and read it at the same time you check the token is valid.
IMO, JWT only makes sense when an other entity is doing the authentication of your clients.
I recently got an Apple Watch and having to just tap on my wrist to authenticate is amazing.
Would love to just be able to give a website one way to contact me and have it ping my device to authenticate with faceid, touchid, Windows hello, or an smart watch.
Basically, a magic link on steroids.
The biggest drawback is the inability to revoke tokens without giving up statelessness. Keeping a KV blacklist isn't the end of the world, especially if expiration times for tokens are short. But at that point, the cost/benefit vs cookies+sessions gets blurry.
Some general JWT tips:
* Use a sufficiently long secret key if you're using HMAC based signing (https://auth0.com/blog/brute-forcing-hs256-is-possible-the-i...).
* Use bearer tokens to avoid CSRF attack surfaces.
* Avoid long (or non-existant) expiration times.
I've wrote how to revoke a JWT (https://dadario.com.br/revoking-json-web-tokens/ - caveat: requires a db lookup), but if you are going through the trouble of revoking a JWT, just use a stateful session instead. It's way easier.
You can use JWT to pass along user information to other components within your architecture, that's fine :)
Its fine to be wrong its also hilarious
Basically the developer is responsible for generating & distributing auth tokens for each device that they want to use our service.
This service is designed to fit into games and AR apps, so we didn't want to force our own oauth flow on the end user. This way, the developer can generate a token on behalf of the end user, and distribute it how they see fit. (assuming one token per user, but it don;t overly matter, it's still tied to their account.)
Sure, Branca may compare to just a JWT, but it doesn't compare to a JWS let alone JOSE.
If all you need is stateless auth tokens, use Branca or a good JWT library.
IMHO, the problem is the libraries, not the JOSE(JWS/JWE/JWK/JWT/JWA) standard. IMHO, after ~4 years there's still no good Javascript or Go library for JOSE, but potentially a few good JWT focused libraries.
https://blog.zamicol.com/2018/03/its-jose-not-jwt-pedantic-c...