Ask HN: What's the current sentiment on JWT for stateless auth tokens?

HN threads from 2016-2018 complain that JWT gives us too much rope with which to hang ourselves, and some advocate for alternatives like PASETO instead. Today it's not clear however that any alternatives like PASETO have crossed the threshold of adoption to warrant preference over JWT when choosing a stateless auth token solution.

What solution would you choose today for stateless auth tokens?

373 points | by CoffeeOnWrite 1595 days ago

32 comments

  • dang 1595 days ago
    • Zamicol 1595 days ago
      The first comment from 11 months ago is wrong.

      >JWTs are useful, but there are a few things that are not immediately obvious. >1) They are signed not encrypted.

      This is not true. JWT's can be encrypted, signed, or both (nested). One might first look to see if this misconception is the fault of a poorly written spec, but it's literally in the second sentence of the abstract and plain as day in the introduction. People are simply not reading it.

      https://tools.ietf.org/html/rfc7519

      It drives me mad when people refer to JWT's as basically JWS's, ignoring the rest of the JWT standard and JOSE. The fact that these misconceptions continue to be up voted shows the broad misunderstanding of the standard.

      • falcolas 1595 days ago
        Or, they highlight that the spec is overly complicated. And a complicated spec is very challenging to implement both correctly and safely.

        EDIT: Case in point, all the disagreements and conflicting best practices throughout the threads on this topic.

        • AmericanChopper 1595 days ago
          I think complex specs are fine. Complex and under defined spec are a nightmare. I had to work on a WebAuthn project recently. That spec is rather complex, but makes perfect sense after you take the time to understand it. More recently, I had to answer a very simple question about X.509. After spending half a day reading the RFC (and about half a dozen other dependant specifications), I gave up and concluded that the question did not have an answer, the best I could come up with was some general graph theory principles relating to DIT.
          • speedplane 1595 days ago
            > I think complex specs are fine. Complex and under defined spec are a nightmare.

            Perhaps, but in practice there generally seems to be a correlation between complexity of a specification and holes in the specification (e.g., html, pdf, etc.).

            • AmericanChopper 1595 days ago
              Complexity, whether necessary or not, makes it harder to maintain a spec. But I’d argue that it’s other issues, whether they’re symptoms of complexity or not, that make it hard to implement. Some things have to be complex, but they don’t have to be full of problems.
      • davewritescode 1594 days ago
        Thank you for this comment, I feel very much the same way. The JWT spec isn’t wonderful and it is complex however, having spent the early part of my career working with SAML, SOAP and xmldsig in highly trusted environments it’s actually a breath of fresh air. Those specs were littered with security flaws.

        That said, the class of attacks that relied on the attacker modifying the header of the JWT could have been totally avoided by including the header values in the signature calculation.

      • Bombthecat 1595 days ago
        Or you work with an opaque token. Then no one knows what's inside...
  • munchbunny 1595 days ago
    In my experience, don't use JWT's for carrying application state.

    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.

    • Izkata 1595 days ago
      > though revocation is still hard

      My understanding was that they're supposed to only last on the order of 5-10 minutes, with a fresh one created for the next set of requests instead of reusing one JWT for days. Is revocation still an issue with the expiry so short?

      • sriku 1595 days ago
        The expiry is one of the tradeoffs to be made. We've also used a kind of emergency switch in the system that expires all tokens that are older than a timestamp system parameter. All this does is force token renewal so legit services continue chugging along while the forbidden will be stopped at renewal time.

        In general, I tend to look at token trust as a decaying function of time, irrespective of signatures.

      • snapetom 1595 days ago
        That's what my philosophy is (15 min max) based on my understanding, but in many places I've seen, people set the expiration to something insane like 5 days.
      • save_ferris 1595 days ago
        No, you just have to always keep in mind that if you misconfigure your application to sign a token with no expiry, you will never be able to revoke it. Period.
        • losingthefight 1595 days ago
          I mean, this isn't really true though. If you forgot, you can have your JWT middleware check and if the field is missing, revoke it. There are tons of workarounds here and I have implemented them in several consulting roles. I personally always put a created and expires timestamp, bit if they aren't there, there are ways to fix the situation easily.
        • kbenson 1595 days ago
          Hmm, couldn't you also rotate encryption keys once a day/week, and keep the last one or two available, and if decrypting with the current one fails, try a prior one? Eventually, that token will no longer be readable. It should only ever matter in the weird case where your expire time is screwy, but you've put a bound on how long a token can survive no matter what.
        • ryanisnan 1595 days ago
          No, not period. If you're using an API gateway (which you should be), you can check against blacklisted tokens. The `jti` is your unique token identifier. As long as you have a way of maintaining a blacklist of tokens, this is trivial.
          • nothrabannosir 1595 days ago
            One of the major points for signed tokens is stateless operation. If you need to maintain a blacklist, you lose that, and the question arises: why not just have a whitelist of tokens/UUIDs/... to begin with?

            This is why people suggest "short tokens" as a work-around, accepting a 5min window of unrevokable tokens as trade-off.

            Or, one has to justify that a blacklist implementation is significantly cheaper than a whitelist one. But is it, really?

            • ryanisnan 1595 days ago
              If you have a sole identity provider, or token issuer, the blacklist can be quite simple to maintain. Plus, with short token life spans, you probably aren't revoking tokens very frequently.

              In my experience, usage of the black list occurred with two use cases:

              1) Invalidating all of a user's tokens 2) Alteration of claims that a user's JWT should have

              As far as your applications go, you still have the benefit of not having to bother with checking the state (this is already done by the gateway).

            • munchbunny 1595 days ago
              That depends on the size of your system. I've worked on systems with so many servers that it would be cripplingly difficult to quickly propagate all whitelist updates to all servers in all services that would need to verify against the whitelist, and the alternative of doing a lookup against the whitelist for every request would be extremely expensive.

              On the other hand, you generally expect that you rarely ever need to actually revoke tokens, so you can naturally expect that a blacklist will change infrequently and will remain tiny compared to the whitelist.

              As the size of the service grows, most people converge to a fast train/slow train design: the whitelist is big and is accessed infrequently, and the blacklist is tiny (goes obsolete within the TTL of the whitelist query) and can be pushed out quickly.

              If you're one of the tech giants, it's not slightly cheaper, it's a lot cheaper.

          • GordonS 1595 days ago
            Or more simply, just check that the JWT has an expiry date, and it's a "sane" one - you can do both these checks without requiring a blacklist.
          • je42 1595 days ago
            yep. however, the token is then not "stateless" anymore since you have to take note of the blacklisted state.

            however, once you really care about the security perimeter, i think the requirement/wish "stateless" must be dropped.

        • gregmac 1595 days ago
          You can add this type of thing to your validation code: exp has to be set, can't be in the past, and can be no more than x time in the future (where x is somewhere between what you're actually signing now and the largest value you could ever conseivably want to use without having to push an update to this app).

          One of the biggest challenges with using JWTs is really all these gotchas that you have to think about. This isn't dissimilar to the infamous `alg:none` fiasco. In this case, it's not really about protecting against an attack, but forcing the developer on the other end to think about it. Their quick initial code that doesn't bother setting exp or has it hard-coded to 1000 years in the future will never work, so it had less chance of being left in to cause a security issue later.

        • alboy 1595 days ago
          All such tokens would be effectively revoked anyway since you check the iat timestamp (or lack thereof) at the authorization point.
          • jacobr1 1595 days ago
            Yep, and that is what we do. But we also check to ensure that a secure cipher was used, not none. Many of the "JWT is insecure" type articles (and real vulnerabilities found) were based on the fact that people just used dumb defaults and didn't secure things. So the argument is really that JWT is a footgun without some adult supervision.
        • hoffs 1594 days ago
          When verifying the token you could just check if exp is set and if the lifetime of the token does not exceed your limit.
    • tus88 1595 days ago
      > In my experience, don't use JWT's for carrying application state.

      Wasn't the question about using them for auth, not application state?

      • munchbunny 1595 days ago
        That’s a good point, I was specifically addressing “stateless auth” as an issue of persisting authentication related state on the client side vs. the server side, as opposed to “the authentication system has no state”, since that’s usually the framing of the question.

        In general authentication/authorization isn’t just a binary in or out. For example, you might have to reauthenticate to access password or 2FA settings in your account, so now you have multiple authenticated states. So I made my comment from the assumption that you probably need to decorate the user’s authentication “state” with extra information for your service. In those cases, I was suggesting to only carry that info in the token if you need to cross service boundaries with it, such as if you have multiple front end micro services operating on independent data stores.

      • rayvy 1595 days ago
        > Wasn't the question about using them for auth, not application state?

        Whether a user is auth'd or not can indeed be a form of application state

  • altmind 1595 days ago
    JWT were aiming to be stateless, yet they cannot be stateless if you need them to be revocable. If you keep using plain sessions you got a SPOF, but you are immune, for a whole lot of consistency and cred management problems.

    http://cryto.net/~joepie91/blog/2016/06/19/stop-using-jwt-fo...

    • jchw 1595 days ago
      To be clear though you generally set the validity to be relatively short and refresh often, so that way you don’t have to worry too much; you can then “revoke” a token by refusing to refresh it.
      • 3pt14159 1595 days ago
        But then it isn't stateless, right? Because you need to know which current tokens are unrefreshable.

        To me, JWT works great for things like physical people getting access to a physically isolated building, like a military research site that's disconnected from the internet. Some secure other place holds the private key and signs the JWT token then you can wave in anywhere you need to go until the validity period is up. Then you have to go back to the secure place to get a new key, verifying the same way you did the first time and the secure place can broadcast its public key to the sites you want access to. It's essentially a great mechanism where you don't have constant communication links.

        But I just don't get it for servers. Also, everyone considering using a JWT token should know about the "algorithm none" setting and ensure that their stack isn't vulnerable to it.

        • bgentry 1595 days ago
          But then it isn't stateless, right? Because you need to know which current tokens are unrefreshable.

          You only have to involve state in 1 request every 10-15 minutes upon refresh. All other requests can be done without having to check for revocation. This is a pretty nice real-world tradeoff.

          • abathur 1595 days ago
            While I haven't taken the leap to using a JWT in any of these cases yet and am a little bearish on them, I do also feel like the baby goes out with the bath-water, here.

            Nothing about adopting JWT says you can't still use a full auth check for state-changing endpoints, and use a stateless session to shave some evaluation time off of frequent read-only requests for data that isn't terribly sensitive.

            You probably shouldn't do it lightly or prematurely since it makes it harder to reason about authentication, but I think it's worth considering whenever you're optimizing.

        • jchw 1595 days ago
          Actually creating a JWT token is not stateless, but at least your architecture is not centralized. If your auth server goes down, that’s a problem no matter what.

          A common validity period is around 1 hour, which is good enough that most users won’t need to refresh very many times per day.

          Also: you don’t necessarily need to track tokens that aren’t refreshable. A typical architecture might have a timestamp stored per user that specifies the earliest token creation date that’s valid for refresh. That way you can invalidate all tokens without needing to ever store them; something you might need to do for password reset, for example.

          • xvector 1595 days ago
            > A typical architecture might have a timestamp stored per user that specifies the earliest token creation date that’s valid for refresh.

            Never worked with JWTs but still, can't believe I didn't think of this. It seems like a fairly elegant way to revoke things where your only stored state is a timestamp.

          • kelnos 1595 days ago
            > A typical architecture might have a timestamp stored per user that specifies the earliest token creation date that’s valid for refresh.

            There's a race condition there, though. If you have a revocation event and set the timestamp, it's possible that an in-progress refresh might have a timestamp just slightly after your stored timestamp. Then you have a rogue JWT that can continue to be refreshed.

            Clocks are sometimes not in sync with millisecond precision. Databases don't replicate instantly. Distributed systems just don't work that way.

            • JamesSwift 1594 days ago
              You could instead store a "generation", and increment on revocation events
        • wruza 1594 days ago
          >algorithm none

          I just read about it on Auth0 [0] and facepalmed. Then I went to node-jsonwebtoken to ensure they added an ‘algorithm’ argument to a ‘verify’ call and you guess what [1].

          They added ‘algorithms’, but into ‘options’, so that naive user like me could just skip it and stay open to attacks. That’s auth0’s own module, btw.

          Thanks for pointing that out!

          [0] https://auth0.com/blog/amp/critical-vulnerabilities-in-json-...

          [1] https://www.npmjs.com/package/jsonwebtoken#jwtverifytoken-se...

          • pfohf 1594 days ago
            Use a proper JOSE module like https://www.npmjs.com/package/jose that uses native node's crypto key objects (ergo not leaving you vulnerable to HMAC based validation bypass) and doesn't even implement "none" algorithm.
        • blackflame 1595 days ago
          You always have to authenticate the JWT anyways to verify data hasn't been changed. The stateless part is the fact that the sensitive data is stored in the JWT itself instead of retrieved from a DB. As long as you can validate the HMAC / Signature then you can assume the contents of the JWT haven't been altered and can therefore trust the client's data.
          • aaomidi 1595 days ago
            Authenticating JWT isn't checking the JWT against an external server.
            • blackflame7000 1595 days ago
              How can you validate that it was properly signed without comparing it to the entity's public key?
              • cstrahan 1595 days ago
                Why would you need to make a request to another server for this purpose?

                Hint: you don’t — but I figure taking the Socratic approach may be more convincing.

                • rblatz 1595 days ago
                  You could pre share a public key, but a common way is to use the discovery mechanism in OIDC to automatically manage key distribution/rolling.
                • blackflame 1595 days ago
                  Because else how do you handle key revocation?
                  • aaomidi 1595 days ago
                    Which is the point of the post.

                    If you need to do revocation you need to call an external server.

                    If you need to call an external server why do JWT?

                    • blackflame 1594 days ago
                      Because pinging another server for a few bytes of data and offloading that working memory to the client side is much more efficient than storing the session data in server memory in between requests. Furthermore a single coordinating key server can work in conjunction with many micro-services to simplify architecture, security, and hardware requirements.
          • altmind 1594 days ago
            Which still leaves a window for JWT to be re-played. If you store something valuable, like # of credits left on a users account, the user can spend some, and then re-use an old jwt to spend again.
        • closeparen 1595 days ago
          It’s stateful for the auth service, stateless for the relying party.
      • jayd16 1595 days ago
        The link seems to think this is impossible but I don't understand why.
        • jchw 1595 days ago
          Don’t see the word “refresh” in there. Guessing they are assuming you use JWT identically to how you might use a session cookie, which is not how I’ve ever seen it used, personally.
          • jayd16 1595 days ago
            In the diagram in the bottom right they seem to think you cannot revoke the long term token. I agree that it doesn't align with my understanding of whats capable with oauth2 style tokens, for example.
            • cstrahan 1595 days ago
              That box should probably read: “You can't revoke the long-term tokens in a stateless manner, so supposing you truly manage ZERO state, then you're back to square one.”

              That seems like the charitable interpretation. Note that the author’s point has not been that JWT is useless, but rather that trying to use stateless JWT for sessions is a bad idea.

              If the point of using for JWT was to avoid all server side state in authn/authz flow — which is the case for many, many developers, and that is the intended audience of the author’s post — then one of two things: you either contradict yourself and implement server side revocation for refresh tokens, or you let the lifetime of your sessions be the same as the refresh token — and in the case of refresh tokens with no expiry, the user (or anyone with their refresh token) can stay logged in forever.

      • tibiahurried 1595 days ago
        > set the validity to be relatively short

        unfortunately, that's not good enough when dealing with stringent security requirements like PCI where revoking a token, generally speaking, means the token is no longer valid starting the moment it was revoked.

    • mgraczyk 1595 days ago
      The state necessary to revoke JWTs is easier to manage than session state.

      1. It's small (id per revoked, nonexpired JWT)

      2. It isn't sensitive, nobody learns anything by seeing the list of revoked JWT ids.

      3. It's monotonic. You just maintain a set that you add to. You can clean up expired tokens if you want but that's not necessary for correctness.

      These three items make bugs less likely and make it easier to manage consistency when you can't afford to use transactions everywhere.

      • namibj 1595 days ago
        The monotonicity alone makes the required state _very_ easy. Adding (timestamp, jwt_id) pairs to a monotonic set which you occasionally switch over to a second, fresh set (checking against both, adding to one) requires zero coordination in the critical path. The only coordination required is about when the sets are switched, where you need to ensure that you leave ample time for old JWTs to expire before clearing the corresponding revocation set entries.
      • mikeymz 1595 days ago
        Rather than blacklist JTIs would it not be simpler to keep a valid after date on the user? Any token issued before that date is not acceptable
        • mgraczyk 1594 days ago
          Then you can't have users sign out of device A while remaining signed into device B.
    • whateveracct 1595 days ago
      Revoking per-JWT requires state per-JWT, but you can get away with globally-revokable tokens ('logout everywhere' functionality) with a single nonce-per-entity instead of a nonce-per-JWT, which is a bit nicer.
      • 0xkalle 1595 days ago
        Right.

        One point to keep an eye on is, if you are using (e.g.) AWS API Gateway with a custom authorizer, it caches the authentication response for a certain time.

        This is not a problem of jwt, but makes the 'logout everywhere' and every black and whitelist need some more time.

    • JMTQp8lwXL 1595 days ago
      You can revoke all JWTs by changing the signing key on your server. All previously issued JWTs will be invalid.
      • ceejayoz 1595 days ago
        Sure, but that's the nuclear option. Imagine if Facebook did that every time one account was compromised or they fired a staffer?
        • JMTQp8lwXL 1595 days ago
          Facebook as the largest userbase of any application in existence. Its needs may not equate to your needs. For example, an enterprise b2b app with a few hundred customers could probably "deal with" the nuclear option.
          • TheFiend7 1595 days ago
            Man I'm not sure I agree with that. Blowing up a bunch of your clients that rely on your services randomly because one account was compromised is not acceptable for really any professional business regardless of the number of clients.
            • JMTQp8lwXL 1595 days ago
              "Blowing them up" is a mischaracterization of the situation. You are not mutating their data. You're only asking them to login again.
              • SkyPuncher 1595 days ago
                Actually blowing them up is a completely appropriate description if you have any non-human's relying on JWTs.
                • onion2k 1595 days ago
                  Applications that use authenticated services need to handle being the authentication being revoked. That's fairly obvious regardless of how it happens. If your app doesn't then it's broken.
          • ceejayoz 1595 days ago
            I'd be pretty upset if I got kicked out of a work app every time one of a few hundred companies fired someone (or even had to do a password reset for a security reason).
            • bingotips 1595 days ago
              A multi-tenant system could use a different key-pair for each tenant and only revoke the one for the compromised entity
            • JMTQp8lwXL 1595 days ago
              You don't use a tool for managing your passwords? That's built into most browsers these days.
              • ceejayoz 1595 days ago
                The issue is not remembering the password.

                The issue is I just logged in 90 seconds ago, typed up a few paragraphs, and when I go to submit I have to do it again, because someone in another company using the tool got phished and needs a new password.

                It's frustrating enough when Gmail makes me put my password in after 30 days and I just clicked into an email I wanted to read. Having it happen all day long would make me want to kill someone.

                • JMTQp8lwXL 1595 days ago
                  I wasn't suggesting mutating the signing key multiple times per day or once per 90 seconds. At that point, you might as well just have a very early JWT expiration timestamp specified.
                  • ceejayoz 1595 days ago
                    The comment thread started with "if you need them to be revocable". Any tool with "a few hundred [enterprise] customers" needs to be able to revoke access for terminated employees, compromised accounts, and the like, and those revocations will occur frequently and in many cases need to have immediate impact.
      • rvz 1595 days ago
        So now every user has to log back in again every time you upgrade your server, simply changing the signing key or when your backend gets compromised.

        Additionally JWEs don't support forward-secrecy meaning that I can MITM and collect all JWEs passing through, find the key in your compromised backend and decrypt ALL these collected tokens.

        No need to do this with JWTs since they're unencrypted by default.

        • JMTQp8lwXL 1595 days ago
          Your server shouldn't be getting compromised on a regular basis. The occasional black swan event occurs, and sometimes you have no other choice.
          • staticassertion 1595 days ago
            Users get compromised though and will want to revoke sessions. But this is why you just set a time limit on your JWT, so that they can revoke and within N minutes the old sessions will die. Just keep N low.
            • wcip 1595 days ago
              >Just keep N low.

              "Your self driving car has been compromised, but don't worry sir the attackers will relinquish control at some point in the next 30 seconds"

              In my view JWT are fine so long as you don't really care about whatever is they are being used for.

    • nicoburns 1595 days ago
      It's not stateless, it just uses a blacklist instead of a whitelist.
    • pierreocinom 1595 days ago
      An approach I have used in the past is including the optional `kid` header. The key id can be matched to the appropriate key needed to verify the signature. If you associate every user with a key, that means you can also delete any key and thus revoke the jwt of a particular user.

      In this case obviously you have a persistence layer for the keys and can't claim to be absolutely stateless.

      https://tools.ietf.org/html/rfc7515#section-4.1.4

    • stephenr 1595 days ago
      > If you keep using plain sessions you got a SPOF

      What single point of failure is inherent with plain server side sessions and a session cookie?

      • ratherbefuddled 1595 days ago
        The server.
        • stephenr 1595 days ago
          ... ok so assuming you then don’t have a HA environment (Really!?) if the server is down the sessions and the tokens are irrelevant because there’s nothing being served and nothing to use/check them and provide back resources.
        • james_s_tayler 1595 days ago
          You don't have to store them purely in-process. The session data itself can live in Redis. You can scale sessions beyond a single web server.
    • jayd16 1595 days ago
      So wait, why does the refresh token not work? Why wouldn't you verify user permissions when generating a new access token?
      • cstrahan 1595 days ago
        Remember that the author’s intended audience is developers who want to use JWTs specifically to avoid server side state in the authentication/authorization logic. The point is that, if you want to revoke the refresh token, you have to maintain a blacklist somewhere, and now you’ve contradicted your original goal of avoiding all state, which means that choosing JWT for this particular purpose was illogical, and probably warrants further thought. (TBC, in logic, if your hypothesis leads to a contradiction, then your hypothesis must be false, which is exactly what we’re seeing here in this scenario.)
        • kelnos 1595 days ago
          I don't see this as rendering JWTs useless, though. If you have a 10-15 minute validity time, and you only check for revocation on refresh (and perhaps, optionally, on sensitive operations), then you don't have to check the the revoked-tokens table on every request, which means your database doesn't have to scale up nearly as much.

          And since the IDs in the revoked-tokens table only matter for the duration of token validity, you can prune the table pretty often, meaning necessary space needed in the DB is relatively small.

          It's certainly more complicated than just dealing with stateful session tokens, so you might decide that the trade off isn't worth it, though.

        • james_s_tayler 1595 days ago
          I disagree. If you make an API Gateway responsible for that concern then it's the only thing that needs to maintain state. The blacklist itself probably kept in something like Redis and the API Gateway just checks against it. Then all downstream services get the benefit of JWT in a "stateless" fashion as advertised. That is, none of the downstream services know or care about any state. They get a request with a JWT and if it has the right claims, it services the request.
        • 0x5345414e 1595 days ago
          > revoke the refresh token, you have to maintain a blacklist somewhere

          Store CreationDate in the refresh token. Store RefreshTokenInvalidBefore in the user record. When refresh is attempted, if Token.CreationDate <= User.RefreshTokenInvalidBefore, reject the refresh. The only drawback here is that it would sign the user out on all devices. However, assuming this is because of a password or token compromise, that's likely the least of their worries.

      • msbarnett 1595 days ago
        You need a really short refresh cycle for that to be useful to customers. If your customer FooCorp fired Bob, they want to be able to disable his access immediately, not in 3 days when his access token next needs a refresh.
        • jayd16 1595 days ago
          15 minutes seems to satisfy most use cases.
    • m-i-l 1595 days ago
      For more secure apps we use single use tokens and expire within a very short period of issuance, i.e. invalidated upon use, and exp (expiry) set a few seconds after iat (issued at). Not optimum for performance because you need to get a new token with every request, but means you never have to worry about having to revoke them. Not heard of anyone in the finance sector using JWT for session management, but that's not what they're for.
    • notyourday 1595 days ago
      Of course you can. Put your auth behind a sane CDN with TTL of forever, the kind that allows tagging an arbitrary number of objects with a single tag and allow to purge objects matching a tag in a single call within a few milliseconds.

      Tag them with sec-uid, sec-uid-dev-id, sec-devclass, sec-we-dont-like-user etc to group them together.

      Want to kill sessions of just user uid? Hit a purge endpoint that purges all objects with sec-uid. Want to kill a session for a specific user for a specific device? Hit the purge endpoint that purges all objects with a tag sec-uid-sec-devid. Want to logout all users on an iPhone because "oops, security bug in a version we rolled out"? Hit an endpoint that purges all the docs tagged with sec-devclass of an iphone.

      You don't even need to remember tokens you issued.

      • jakelazaroff 1595 days ago
        You are describing stateful authentication.
        • notyourday 1595 days ago
          Nope. You don't even need to know you issued those tokens or their state. You don't ever assert a state or check it. You force its recompute via cache bust.

          You don't need to know a token of jakelazaroff. You don't need to know its state. You don't even need to know if it exists.

          You know that a token associated with jakelazaroff iphone if it exists will have a tag jakelazaroff-iphone because every token associated with <user> iphone will always have a tag <user>-iphone since you always tag a token of any <user> on an iphone with a tag <username>-iphone when you issue the token.

          • jakelazaroff 1595 days ago
            I don’t understand your explanation, but the words that you’re using (e.g. “purges”, “cache”) indicate that you’re describing a stateful system.

            Imagine you’re writing your API on AWS Lambda, so memory and the file system are not shared between requests. A client presents your API with a token. Using no external resources (no database hits, no network requests, etc) how do you determine the veracity of that token?

            Edit: I think I understand what you’re saying. Using a CDN that will let you “tag” resources and conditionally provide access based on whether HTTP headers match those tags, you issue tokens to clients and add or remove tags to give and revoke access. The CDN determines whether a given tag can access the resource, and your application doesn’t worry about authentication.

            This is still stateful. The tags are the state!

            • notyourday 1594 days ago
              > Using a CDN that will let you “tag” resources and conditionally provide access based on whether HTTP headers match those tags, you issue tokens to clients and add or remove tags to give and revoke access.

              The tokens are the resource.

              Your auth is what tags the tokens. Your auth is the only entity that is able to compute the tags that would match the criteria of the tokens to invalidate them.

            • notyourday 1595 days ago
              Correct. I can assert a validity of the token without touching any database. Not only that, but the API does not even need to compute what it is. That's what makes it stateless.
              • jakelazaroff 1595 days ago
                It’s not stateless, you’re just trading a database for “tags”. This is exactly the same as if you just placed a stateful authentication service that checks a database in front of your API. How do you think the CDN works?
                • kelnos 1595 days ago
                  I guess the idea is that it's "stateless" in the sense that you don't have to maintain the state yourself, and the CDN will do it for you? I mean... okay, I guess the point of being stateless is that you don't want to deal with the scaling and reliability issues around storing state, so pushing that responsibility onto a third party (whose uptime is required to get to your site anyway) is "stateless" from your perspective.

                  I certainly wouldn't call that "stateless", but it does fulfill the main reason why you might want to be stateless, that you don't have to maintain any state yourself.

                  • jakelazaroff 1594 days ago
                    Exactly — it's basically the same as writing your own separate authentication service, or using Auth0/Cognito/Firebase.
                  • notyourday 1594 days ago
                    The reason why it is stateless is because there's no state associated with a token that I have to maintain.
                • notyourday 1594 days ago
                  You do not maintain the tags. You compute the tags and you do not care what so ever if the tag ever matches anything.
                  • jakelazaroff 1594 days ago
                    It doesn’t matter who maintains them — the tags are still state. It may be stateless from your API’s perspective, but the system as a whole is still stateful.
  • rvz 1595 days ago
    Today I would still use alternatives like PASETO [0] or Branca [1] tokens which the latter is a fernet-like secure alternative to JWTs.

    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.

    [0] https://paseto.io/

    [1] https://branca.io/

    [2] http://cryto.net/~joepie91/blog/2016/06/19/stop-using-jwt-fo...

    • GordonS 1595 days ago
      > 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)

      While a session ID doesn't require parsing, it is useless on it's own; a fairer comparison would be: time to validate and parse/deserialize a JWT vs time to retrieve session data from the backing store (e.g. database, redis).

    • cordite 1595 days ago
      Another interesting one is Macaroons [1], although the implementations have not had much activity since 2014.

      [1] https://ai.google/research/pubs/pub41892

    • GordonS 1595 days ago
      I've come across PASETO before, but never heard of Branca before.

      I certainly like the lack of footguns in PASETO, but I'm curious about how much real-world adoption it (or indeed other JWT alternatives) really have?

      • duelingjello 1592 days ago
        Popularity is never evidence of rigor or soundness. Lots of people do dumb things like lemmings.
        • GordonS 1592 days ago
          While I like the sentiment, it's a little naive; I want to use something that's got real community traction, and is going to be around long-term.
    • JaviFesser 1593 days ago
      Oh! I love fernet (not the library, but the alcoholic beverage)
  • 013a 1594 days ago
    I think, philosophically, they're interesting, but in practice the statelessness ends up not being a huge benefit.

    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.

    • charrondev 1593 days ago
      You could keep the role information in memory pretty easily though. A lot setups don’t have that many roles (even big enterprise deployments I’ve seen tend not be more than 1000, and that’s pretty extreme).

      The roles per user and auth of the user on the other scales linearly with users and is harder to keep in memory.

  • authaway 1595 days ago
    JWTs aren't just bad because they embody poor cryptographic engineering, but they are also bad because stateless authentication in itself is poor security engineering for almost every application.

    > 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.

    • ravenstine 1595 days ago
      It's kinda funny how some people think that this would be a performance problem, but it's something that computers and programming languages are specifically designed to do really well.
      • bpicolo 1595 days ago
        KV lookups with no dependent data are pretty much infinitely scalable with modern systems.
        • andyroid 1595 days ago
          It’s not the lookup that is the cost but the network call.
          • bpicolo 1594 days ago
            That's darn cheap in modern systems, and most are doing a plethora of network calls per request either way. .5% overhead won't matter for a long time.
  • jrockway 1595 days ago
    I am fine with using JWT-alikes for bearer tokens. Good for one request or a very time-limited duration.

    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.)

    • GordonS 1595 days ago
      > 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

      I've done something similar, to "terminate" Windows authentication at an API gateway, so downstream services can run on any platform, and don't have to deal with the vagaries of Windows auth.

      JWTs worked very well for this use case (obviously any other kind of token would have worked too, such as PASETO).

    • Fellshard 1595 days ago
      Add 'issuing date' to the token, revoke all before a given issue date by a single date field in your auth table. Effectively clears all tokens. Would that work, if done up front?
      • jrockway 1595 days ago
        You have to check this date on every request.

        I think, on some level, you can make a revocation database scale better than a validity database. You store the revocation in some durable datastore. Then you have some service in front of this that calculates the entire set of revoked tokens, and pushes that to each auth gateway. Then the auth gateway can check if a token is revoked without putting any load on a database. It has to do this for every request, but you can scale the auth gateway horizontally rather easily.

        (When an auth gateway starts, it gets a copy of the full revocation table again.)

        On some level, you do need the ability to push revocations to your auth server, because when you hit the kill switch on a session, you really want it to close all their open TCP connections (HTTP/2, Websockets, SSH, etc.)

        Having said that, starting simple is the best approach. I used MySQL to store sessions at my last job. Every request went from Envoy -> ext_authz -> authentication/authorization service -> MySQL and this whole flow added only 1-3ms of latency per request. Someday you will hit scaling limits of using MySQL for this, but it's a long way in the future. Do the simple and reliable thing first, then make it complicated later.

        • abathur 1595 days ago
          I'm bearish on JWTs in many cases for reasons enumerated here and elsewhere.

          But I do use them in one place with a revocation scheme similar to this. On init, instances build an in-memory bitwise blacklist that token IDs are checked against.

          This arrangement probably already implies this, but just in case: this is at a very small scale where the complexity of pushing revocations isn't justifiable, power granted to the token-holder is limited and easy to clean up if misused, and revocations are so rare that restarting instances to update the blacklists is tolerable).

        • DenisM 1595 days ago
          > 1-3ms of latency per request.

          Is that a big problem in practice? I always wonder about the tangible benefits of this approach.

          • jrockway 1595 days ago
            Yeah, I am quite OK with these numbers. The sessions-in-a-database-table is fast, simple, and accurate.
      • robmccoll 1595 days ago
        Optimization if revocation isn't common: - Keep a last revocation time somewhere that is cheap to frequently poll (Redis) or broadcast it to all your nodes - Keep a revocation table - Use iat and exp with your JWTs - On revocation update the table and the last revocation time. - On validation, only check the revocation table if iat < last revocation time. If you have to check the table, reissue the JWT with the same claims and exp but updated iat.
      • ceejayoz 1595 days ago
        Every time you have to revoke a user's access, the entire organization has to log in again?
        • Fellshard 1595 days ago
          Per user field.
          • ceejayoz 1595 days ago
            You've given up the benefits of a stateless token if you're looking in the database to check it's state all the time.
            • Fellshard 1595 days ago
              That is always the key point it comes back to. Thanks.
  • DGAP 1595 days ago
    If you like Ptacek, read this: https://latacora.micro.blog/2019/07/24/how-not-to.html

    But more importantly, why do you need stateless auth tokens?

    • spookthesunset 1595 days ago
      > why do you need stateless auth tokens?

      So you aren't hitting some validation server on every HTTP request to validate a token. Said validation server adds a very nasty point of failure & potential for page latency.

      Going mostly stateless via JWT lets you balance the desire for fast token revocation times and load on your auth server. Even if your revocation time is a minute, meaning your clients need to refresh their token once every sixty seconds, that can still substantially lighten the load on your auth server. High security stuff can always validate the token on every request but stuff that doesn't matter as much can have a much more policy.

      • eropple 1595 days ago
        > So you aren't hitting some validation server on every HTTP request to validate a token.

        This is not a real problem for the 99.9% case and you can add another nine if you aren't defaulting to "extreme conservative"on your risk analysis. A session token lookup in a Redis or a Postgres is completely trivial and cheap.

        ("But my auth service is over a network link," cries the architecture astronaut, who now has more problems and fewer solutions. Build simpler things, you almost certainly don't need more complex and you can build better solutions than JWT when you need them.)

        • spookthesunset 1595 days ago
          The only architecture astronaut around here would be the one who makes up requirements like “needs to validate every request against a backend auth server” and “network calls to an auth server are cheaper and easier than local token verification”.

          The crypto used for JWT not some brand new space age thing. Public key cryptography has existed for decades now.

          JWT is a very elegant solution to the problem space once you understand what it does. I get the feeling the actual architecture astronauts are the folks around here dismissing it.

          • eropple 1594 days ago
            Implementing a logout-all-sessions function is not the behavior of an architecture astronaut--but building distributed auth because you footgunned yourself with microservices certainly is. And to implement that with JWT you aren't doing local validation because you can't do validation without implementing revocation and you've devolved back to checking a store for validity anyway.

            That might not matter to you because you might not work on things that matter and that's fine. If what you work on doesn't matter, do whatever you want, but if it does, don't use JWT.

        • zimpenfish 1595 days ago
          I worked at a place which had local server in-memory cache talking to local Redis cache talking to shared Redis cache talking to MySQL session tables and the traffic to the actual session tables was still heavy enough that they had to sit on their own DB cluster. Switching to signed session cookies encoding a few bits of information (or JWTs if you prefer a mad complicated outsourcing) would have been a huge win on that point.
          • cellularmitosis 1595 days ago
            What sort of traffic levels were you hitting?
        • magicalhippo 1595 days ago
          > "But my auth service is over a network link," cries the architecture astronaut, who now has more problems and fewer solutions.

          There are at least a few cases where a central auth service makes sense. Gov't here uses it for example, so that the services from all the various departments and whatnot don't have to roll their own auth.

          • eropple 1594 days ago
            Certainly there are! Nobody's saying otherwise. But they are few, they are far between, and if they manage anything important they should be using OAuth to validate identity and provide credentials that the services check on-request.
            • magicalhippo 1594 days ago
              That's exactly what they're doing, using JWT for OAuth 2.0 bearer tokens.
              • eropple 1592 days ago
                Which is not checking on-request. If a token is invalidated, it must be rejected inline. Otherwise, you're just fucking around. Which, if you aren't doing anything important, sure, fine--the problem is that most of the folks who leap to poorly-specified jank like JWT are doing important things with tools they don't understand and the people that are impacted are downstream of them.
                • magicalhippo 1590 days ago
                  Not sure what you mean, and I might have explained their setup wrongly, I'm no expert in this.

                  I ask for an access token from auth server, I pass access token to API server, API server optionally checks with auth server if token is ok, or if token is self-contained, verifies signature, checks expiration time etc.

                  Obviously self-contained tokens cannot be revoked, they can only expire.

                  For this service, JWT is used when requesting an access token, and as an access token for self-contained tokens.

        • andyroid 1595 days ago
          Network latencies and round trips will almost certainly be the primary source of performance issues in any larger microservice environment. If you don’t need that level of scale, that’s great. But once you do, JWTs are perfect for carrying information across the network that may be verified without extra network calls involved.
          • eropple 1595 days ago
            > But once you do

            Sure.

            The vanishing minority of projects ever get to that point.

            Didn't we internalize YAGNI literally a decade ago?

            • spookthesunset 1595 days ago
              A vanishingly small minority of projects need the ability to instantly revoke a token on every HTTP request. And even then there is nothing stopping you from doing so with JWT.

              Know your facts. And YAGNI and all that...

              • eropple 1594 days ago
                "Logout all my sessions" is basic decency towards your user.

                I get that it's hard with your bloggable thing, but it's better for the people on the other end.

        • spookthesunset 1595 days ago
          JWT is much simpler architecture than looking up session tokens every request.
          • eropple 1595 days ago
            Until you need revocation.

            Which is to say until you need a working authentication system.

            JWTs solve a nonexistent problem in the 99.9% case but are so very, very bloggable that they've brainwormed the population but good.

            • spookthesunset 1595 days ago
              It’s a trade off dude. You trade off the ability to revoke a token instantly for fewer backend calls. For most parts of your site (99.9%) that trade off is fine. For the parts where it isn’t fine you... call the auth server every request.

              JWT doesn’t mean you give up anything....

          • GordonS 1595 days ago
            That's demonstrably not true; it might be more efficient for loaded systems, but it's certainly not simpler.

            Looking up an ID in a database is much simpler that using JWTs (which involve crypto) and handling revocation.

            Libraries might hide a lot of the complexity of JWTs behind abstractions, but that doesn't mean it doesn't exist.

            • spookthesunset 1595 days ago
              Oh please... you are seriously going to argue it is less complex call a database or redis than it is to locally validate a token using proven crypto methods that have existed for decades?

              If you are gonna play the “look under the layers of abstraction to count true complexity” game.... your assertion falls apart in a hurry. Calling a database or redis every http request is a hell of a lot more complex in terms of call stack, configuration, network dependencies and library support than JWT.

              But it is a stupid way to frame your argument to begin with. Both ways abstract all their doings behind a library. Both probably have almost the same general configuration foot print. And JWT has the benefit that you can still treat it like a session token and validate on every call for parts of your site that need it. Most sites do not need to instantly revoke a token everywhere!

              The number of detractors around here who don’t understand that last point is pretty sad...

              • GordonS 1595 days ago
                While I think your response is overly harsh, I could have phrased my argument better. What I'm getting at is that the JWT spec has issues, JWTs are complex to get right, and they have (notorious) encryption footguns. Connecting to a database is a relatively simple affair.

                For the record, I'm not a JWT "detractor" (if you look elsewhere in this thread you'll find a comment where I used it to good effect).

  • lightwin 1595 days ago
    JWT helped me to achieve authentication and authorization without needing to make a trip to database on every API call. I use to store user role code in the token.

    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.

    • ossworkerrights 1595 days ago
      Why do you need a db call for api request when you can just cache session data?
      • ninjakeyboard 1595 days ago
        In memory caches have scalable concerns and require sticky load balancer. You'd need to decentralize the cache (eg create a db for the session information) to allow horizontal scaling of services so this approach is generally considered old-school.

        JWT has its own slew of problems, most of them are temporal (eg invalidation of all sessions), usability (eg short expiry), or additional security vectors (many poor JWT implementations, accidentally authenticating invalid tokens w/o signing, careless storage of readable values)

        • ossworkerrights 1595 days ago
          Hmm never had an issue with in memory caching and scalability (except in the old days of memcache). One can send a unique and hard to guess pair of identifiers and drop the lb stickiness. anyway depends on the use case, but i feel like given the symptoms you describe there are a few other ways of doing it without jwt.
          • ninjakeyboard 1593 days ago
            For sure - they're just considerations/complexities if you need to quadruple your service infrastructure for black friday or what not. I don't feel JWT is often appropriate - I wrote one of the early scala implementations so have seen the lifecycle of a security library.
      • andrewxdiamond 1595 days ago
        JWT are effectively that, a signed token that contains the session information.

        You could build a session cache, either in memory or out of process, but it would still be more work than the token approach

      • dyeje 1595 days ago
        Typically, before stuff like JWT was popular, you would store a session in the db and the session id in a cookie. Then you would hit the db each request to check if the session was valid.
        • ossworkerrights 1595 days ago
          Well not really. Storing session data in the db can hit your performance pretty bad. Storing them in mem is a better option.
          • latortuga 1595 days ago
            These are not mutually exclusive options. Redis is a database and runs in memory.
            • ossworkerrights 1595 days ago
              Actually no, it’s an “in-memory data structure store, used as a database, cache and message broker.”.
          • dyeje 1594 days ago
            Yea, that's why people moved to auth headers.
      • rblatz 1595 days ago
        I’ve found that writing starless services makes my life significantly easier. Also I may need to query several apis to render a single page. Each one needs to know who is calling it.
  • ceejayoz 1595 days ago
    Frankly, I just went back to sessions.

    Everyone thinks they're building the next Facebook, but most of us aren't gonna stress out even a single Redis instance.

    • jcadam 1595 days ago
      Yea, I went back to sessions (with Redis) as well. So much simpler, since all of the major web frameworks/libraries have much better support for traditional sessions than JWT...

      One place I still might use JWT is in service-to-service auth.

    • MuffinFlavored 1595 days ago
      In that same mindset, why not just do a JWT in a cookie then?
      • schwap 1595 days ago
        Because then you have all the headaches of JWT, without any of the benefits of stateless auth tokens.
        • TobiasA 1595 days ago
          Which headaches would that be?
          • dewey 1595 days ago
            That you have to keep a white/blacklist if you want to revoke a token.
          • mychael 1595 days ago
            Blacklisting is only half the problem. Trying to emulate the same UX of regular sessions (staying logged-in etc) is the bigger pain point.
      • blackflame 1595 days ago
        Because trusting the client with data is always a risky proposition.
        • jdminhbg 1595 days ago
          Sessions are no different in that respect. You need to sign your JWT or session cookie.
          • bob1029 1595 days ago
            I see no reason to sign a session cookie that was issued by and will be validated against some authentication service. Especially if the cookie is sourced from a cryptographically-secure pseudorandom sequence of bytes which is sufficiently long to avoid collisions with other such sequences (e.g. 256 bits of entropy should typically do per session cookie).

            In my implementations of such schemes, I will typically feed the CSPRNG output with a time-based salt into SHA256 or SHA512 in order to generate the final token, which is simply stored on both ends (user session db row on server & cookie on client). At this point, the server can simply 1:1 the supplied client token with the row in the database to determine if the session is valid and which claims to return (or which validated final server response to return as the case may be).

            Advantages with using a token made out of pure entropy soup are that it's consistent throughout the entire user's session, and confers absolutely zero information regarding the nature of that session. Disadvantages are honestly unclear. I feel like JWT and other stateless schemes started as a bandaid to re-couple the authentication domains of disparate business services, but by way of the various clients.

            • blackflame7000 1595 days ago
              This property you use is known as an ephemeral session key and is a requirement for perfect forward secrecy. (Not being able to crack previous messages by compromising a key in the future)
          • ceejayoz 1595 days ago
            You can store data in the server-side session the user is never intended to see. If you want to store that in a JWT, you're going to have to encrypt it, not just sign, and even that may clue them in that something's going on - if you perform some potentially spammy act on a site and suddenly the JWT gets updated with a big encrypted block, you probably know you tripped some flag.
          • derptron 1595 days ago
            Signing session cookie? wut?
      • shantly 1595 days ago
        You can. What does that have to do with traditional sessions?
  • AndrewStephens 1595 days ago
    Who cares what the current thinking is - define your problem and implement the solution that makes the most sense to you.

    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.

    • ceejayoz 1595 days ago
      Some of the mistakes people commonly make - insecure ciphers, for example - should've been addressed in the standard.
  • codegeek 1595 days ago
    One of the secrity experts here at HN always recommends against it for auth. Go to the search box on HN and type "author:tptacek jwt". Make sure you are searching within comments. You will see his multiple responses over the years.

    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 :

    https://github.com/alexedwards/scs

    • spookthesunset 1595 days ago
      > I have mostly stuck to plain old server side sessions that are easy to revoke.

      But you have implicitly made a tradeoff. Your front-end infrastructure now has a very strong dependency on your auth server. Any minor hiccup in the auth system will blow up your downstream clients. Worse, in large sites you will be sending a ton of traffic to your auth server.

      You've also introduced a source of latency to your page-load times as each request now needs to call the auth server to validate the token. Whatever the response time of the auth system now gets added to the front-end response time.

      Going with tokens that can be validated on the front-end system can dramatically lighten load on your auth system and reduce your front-end response time.

      The only major trade-off is you can't kick somebody out instantly. The bad-actor can do whatever until the token expires--a knob you control. And even then, for shit that matters, you can always have the front-end server validate the auth token on each request anyway.

  • madhadron 1594 days ago
    My sentiment: use sessions in cookies the way people have for years if what you're doing is managing sessions.

    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.

  • StreamBright 1595 days ago
    I think there are two great options:

    - https://paseto.io

    - http://macaroons.io

    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.
    • jiofih 1595 days ago
      What makes macaroons great? I read the whole documentation and the macaroon.js docs. It seems to be under-documented, the library last updated 3 years ago. I couldn’t really grasp how the mechanism is safe re. clients adding “self-attenuations” that would amount to a DoS on the receiving service. Is anyone using this in production?
      • tptacek 1595 days ago
        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.

        • jiofih 1595 days ago
          > nothing’s stops discharge macaroons from containing embedded third-party caveats ... to consider

          My understanding is that the receiving app has to contact each third party to retrieve the “discharge macaroon”. What stops someone from adding a bunch of dummy caveats to cause *N requests on the server?

          • arnarbi 1595 days ago
            No, the discharge is indicated to the verifier cryptographically. The user of a 3p-caveated macaroon has to request that discharge from the 3p before sending it to the server.
            • jiofih 1594 days ago
              I don’t know what else to say - maybe the macaroonjs documentation is wrong? Full quote:

              > nothing stops discharge macaroons from containing embedded first- or third-party caveats for the verifier to consider during verification.

              So the user requests discharge tokens on his own, but the discharge tokens have to be verified by _my_ server and might contains nested third-party caveats which I’ll have to verify.

              • arnarbi 1593 days ago
                If the discharge has another 3p caveat, then generally you'd have to get that discharged also before sending it to a server.

                Either way, in each deployment a server supports a set of caveats that makes sense and rejects others.

                Or that's the intention of the original idea (I'm an author of the paper). I can't speak for macaroonjs specifically.

    • kcolford 1595 days ago
      Are you sure you're protected from CSRF from older browsers? There's still plenty of IE going around on old desktops in libraries and such.
      • IggleSniggle 1595 days ago
        Not OP, but wrt to enterprise apps, SameSite protects from CSRF even on IE since June 2018 update. https://caniuse.com/#feat=same-site-cookie-attribute
      • StreamBright 1595 days ago
        Based on the user base this is a negligible minority for us, that we do not want to care about. We can simply display an error message saying that you need to use a newer version.
  • MadWombat 1595 days ago
    Everyone seems to be posting the "stop using JWT" article from 2016. It has a lot of merit, but I think there is small logic hole in it. When the second part attempts to address the issues of token revocation, its only argument is "what if your blacklist is down?". But that is silly. Blacklist is part of your authentication process, if it is down you don't authenticate. Its like asking how would you serve your API if your API server is down. You won't, your server is down.

    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.

    • NewEntryHN 1595 days ago
      The argument is that the blacklist is as much a SPOF as a session server would be. The blacklist kills the statelessness.
      • james_s_tayler 1595 days ago
        Does that negate all the benefits though?

        If a single component of your application maintains a little state, say the API Gateway, and all the downstream services simply get a clean JWT they can trust with all the right claims in it?

        I'm thinking this is still nicer than having every downstream service also having to check auth claims against some datastore.

        • jeltz 1595 days ago
          Yes, because then the API gateaway could instead just use traditional sessions and attach relevant data when forwarding the request downstream.
      • enraged_camel 1595 days ago
        Exactly. Even if it's not a SPOF, it becomes yet another piece of architecture you need to worry about distributing and scaling (if you're at the point where JWTs are attractive to you due to their scalability).
    • zackbloom 1595 days ago
      It's also possible to do your token validation in something like Cloudflare Workers and store your blacklist in Workers KV. That would mean it lives all around the world closer to your users than your origin, making it unlikely it is adding meaningful latency to check it.

      Disclaimer: I work at Cloudflare

      • tggg33 1595 days ago
        But there’s a limit of 5000 requests per 10 minutes with cloudflare workers. This kind of usage will never go well with that limit.
        • jsty 1595 days ago
          Where did you see that? I've skimmed their limits page [0] and there doesn't seem to be any request limits for paid plans.

          [0] - https://developers.cloudflare.com/workers/about/limits/

        • kentonv 1594 days ago
          There is no such limit. We have individual customers doing hundreds of thousands of requests per second.

          (Disclosure: I'm the lead engineer for Workers.)

  • andyroid 1595 days ago
    JWTs and sessions are not in any way orthogonal in a system as a whole. We use JWTs primarily for scalable backends - if a session is setup or not in the front end is not a concern for the API backend services. In a microservice environment there could be many of these - that’s the whole point after all. And with JWTs being sent to these they can simply verify the integrity of the caller without asking a central authority. Coupled with OAuth2 and OIDC as protocols for delegation/federation and you have a system that scales extremely well. Of course, it might not be the first concern that needs to be addressed in a small startup but that doesn’t mean it doesn’t have a place.
  • Znafon 1595 days ago
    In my experience, the idea that JWT is stateless is wrong. When your client log-out you will need to keep the token in a blacklist and check all requests against it to make sure it is not reused until it expires.

    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.

    • ravenstine 1595 days ago
      > When your client log-out you will need to keep the token in a blacklist and check all requests against it to make sure it is not reused until it expires.

      Sounds like a great way to DOS a server by running out its disk or memory space. (unless there's some sort of rate limiting in place)

      • Znafon 1595 days ago
        How does keeping a short token in redis or other would make the application easier to DOS than any other resource?
        • ravenstine 1594 days ago
          Because keeping a blacklist means keeping a list of all invalid tokens that haven't expired. If a user creates a crapload of sessions, you have to keep a running list of all the invalid tokens until they expire, which creates a few problems. You now have to have some mechanism to clear out tokens that have expired, which totally defeats one of the benefits of JWTs. And keeping a blacklist opens up the doors to someone slamming your /session endpoint, eventually running out your storage and/or memory because the blacklist will just keep growing. Sure, you can build in rate limiting, which you should have anyway. The reason I think this is still a problem is that a lot of amateurs are going to go straight for JWT and are too inexperienced or lazy to implement rate limiting.

          But why add all this complexity? Just have a whitelist, and you avoid these problems.

          • Znafon 1593 days ago
            > You now have to have some mechanism to clear out tokens that have expired, which totally defeats one of the benefits of JWTs.

            I think we are making the same argument, JWTs are supposed to be stateless but can't as you need to be able to logout.

            > And keeping a blacklist opens up the doors to [...] running out your storage [...] because the blacklist will just keep growing.

            > But why add all this complexity? Just have a whitelist, and you avoid these problems.

            How does a whitelist helps you there?

    • derptron 1595 days ago
      If you require a blacklist, then you are doing JWT wrong.

      If you are using JWT to maintain client state, then you are doing it wrong.

  • jrobn 1595 days ago
    We need FIDO2 or some other standardized security key protocol in our devices.

    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.

  • hashamali 1595 days ago
    JWT bearer tokens have worked well in my experience, though I haven't used PASETO. The main benefit is being able to use the same authentication mechanism for mobile and web apps.

    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.

  • gremlinsinc 1594 days ago
    I was torn, but recently I found Inertia.js and love it. It uses server session for auth, and makes vue a bit like turbolinks, and I'm able to use vue without router/vuex, so for a fullstack but better at backend guy like myself it makes more sense. Look at their pingcrm for a good intro using laravel.
  • andersonmvd 1594 days ago
    Just use stateful tokens because if you are dealing with sessions and you are doing it right, you WILL want to revoke them at the user's will or at some suspect activity in a session.

    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 :)

  • bfrog 1595 days ago
    I feel like JWT is a poor version of aead cookies like rails uses.
  • mooseburger 1595 days ago
    I'm not sure I understand the people claiming you should use server side session tokens instead. How am I supposed to make that work with Angular? I have to be able to send to the client the user privileges somehow.
    • GordonS 1595 days ago
      When logging in, the backend will generate some state (e.g. user privileges) and store it somewhere, alongside a random session ID. It might be stored on disk, in a database or in a KV store like redis.

      The backend returns this session ID in a cookie.

      You store this session ID as a client-side cookie, which gets sent on every request to your backend.

      When your backend receives a request, it will (typically using some kind of middleware) lookup the session ID in the backing store and deserialise the state.

      Sliding expiration is typically used, so as long as you keep making requests, you'll remain logged in.

      Revoking a single session ID is very easy, since you've just deleting a single row/key/line from your backing store.

    • jgalentine007 1595 days ago
      It's pretty easy with authentication cookies and csrf tokens. I switched back to sessions too after messing around with jwts for a bit.
  • lifeisstillgood 1595 days ago
    I would be grateful if anyone could point to a "how to build a PKI based (client and server certificate based) ecosystem"
  • khana 1595 days ago
    do: signed and ecrypted JWT, sent to client as a secure, http-only cookie
  • rolltiide 1595 days ago
    Where’s that guy from that Oauth company that always pushed JWT, I think he was with Okta

    Its fine to be wrong its also hilarious

  • blackflame 1595 days ago
    The biggest thing to worry about is a hash length extension attack. https://blog.skullsecurity.org/2012/everything-you-need-to-k... This requires avoiding the use of a MAC hashing algorithm such as sha1 or even sha256 because it's possible to append data and generate a valid signature from a previous oracle. Alternatively, you could use SHA2 to generate a 512-bit key and then truncate the key to 256 or use an HMAC
  • TomMarius 1595 days ago
    Even if your tokens are stateful, they should be signed.
  • markandrewj 1595 days ago
    This isn't a technical answer, or me saying that there are not better options, however with JWT's being one of the corner stones of Oauth and OIDC, it would be hard to argue that there are not successful implementations.
  • KaiserPro 1595 days ago
    We use encrypted JWT tokens. I'm not sure it was the best choice, but it was the simplest for our needs.

    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.)

  • vbezhenar 1595 days ago
    I'm doing everything by hand. Like byte array with timestamp (4 bytes), IP-address (4 or 16 bytes), user id (4 bytes) and so on, then this array is signed and converted to string using base64. I looked into JWT and it was absurdly long. I don't like to waste bytes.
    • peburrows 1595 days ago
      “I don’t like to waste bytes” isn’t exactly a great reason to write off a widely accepted and deployed spec for transmitting data in a trustworthy manner and instead write your own implementation, which most likely hasn’t considered all the attack vectors the JWT (and broader JOSE) spec has considered and accounted for.

      I get the motivation — and I hesitate a little bit to say this — but it’s 2019, and a few “wasted” bytes on your auth token are less than inconsequential in a world where your front-end codebase mostly like “wastes” thousands (if not millions) of bytes.

      When it comes to securely transmitting data, it most often pays to lean on the work and research of others.

      • vbezhenar 1595 days ago
        I prefer to keep it simple. JWT does not look like a simple thing.
    • deathanatos 1595 days ago
      HTTP/2 HPACK compresses headers in such a way that the difference will be largely irrelevant.

      Most connections nowadays are such that latency is overwhelmingly more important than that many bytes.

      Also, IP address? You invalidate me every time I switch networks?

      • vbezhenar 1594 days ago
        Absolutely, if hacker steals token, he'll likely using another IP address, so token is bound to IP address, it's a very important security measure. It's easy to issue new token anyway and address does not change often.
    • klysm 1595 days ago
      Signed how?
  • Zamicol 1595 days ago
    JOSE and COSE fill a void not filled by anything else on the market.

    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...