[HN Gopher] Should I use JWTs for authentication tokens?
       ___________________________________________________________________
        
       Should I use JWTs for authentication tokens?
        
       Author : pantalaimon
       Score  : 243 points
       Date   : 2024-05-27 15:31 UTC (7 hours ago)
        
 (HTM) web link (blog.ploetzli.ch)
 (TXT) w3m dump (blog.ploetzli.ch)
        
       | zie wrote:
       | Not to mention it's ridiculously easy to make JWT's insecure.
        
         | toenail wrote:
         | It's ridiculously easy to make any computer insecure.
        
         | EthanHeilman wrote:
         | Can you provide some examples here using modern JWT libraries?
         | I'm not saying you are wrong or right, but this comment as it
         | is written doesn't add much to the discussion.
        
           | CiPHPerCoder wrote:
           | https://github.com/firebase/php-jwt/issues/351
        
             | EthanHeilman wrote:
             | Thanks for providing this, it is interesting vulnerability
             | to read about.
             | 
             | In terms of JWT vs other ways of doing this, is there any
             | evidence that JWTs are more vulnerable that other
             | approaches? Clearly there are vulnerabilities is other
             | approaches as well.
             | 
             | I buy the statement that bearer authentication JWTs are
             | much worse than proof of possession JWTs, but are bearer
             | authentication JWTs worse than other bearer authentication
             | approaches? What data would you need to argue that position
        
               | CiPHPerCoder wrote:
               | > In terms of JWT vs other ways of doing this, is there
               | any evidence that JWTs are more vulnerable that other
               | approaches? Clearly there are vulnerabilities is other
               | approaches as well.
               | 
               | Contrast JWTs with PASETO implementations when you make
               | that sort of analysis.
               | 
               | i.e., pick any that support v3/v4 and try to attack them
               | the same way that JWT implementations have been
               | vulnerable, or worse ways: https://paseto.io
        
         | bebop wrote:
         | I have not seen an authorization server that makes it easy to
         | configure no signing algorithm or even one that might be
         | considered insecure. Most of the client authentication
         | providers I have used (I.e frameworks) have also forced a
         | secure algorithm, usually starting with rsa 256. So while
         | technically you can use a no algorithm signer, I have never
         | seen this happen.
        
           | CiPHPerCoder wrote:
           | The vulnerability is usually in verifiers rather than
           | signers.
           | 
           | See, for example:
           | 
           | https://github.com/firebase/php-jwt/issues/351
        
       | ramesh31 wrote:
       | So then why does Auth0 use JWTs for everything..?
        
         | zaphar wrote:
         | Because their business is auth as a service and because their
         | database is not your database and they don't want you hitting
         | their database directly.
         | 
         | A similar question to the articles is whether you actually need
         | Auth0 or not. You might but then you are offloading all the
         | issues of JWT's to Auth0 so in theory, probably not in
         | practice, you don't have to worry about those.
         | 
         | For many apps however. You probably don't really need Auth0.
        
           | FerdSlav wrote:
           | As someone that is just attempting to get a better
           | understanding of this aspect of a tech stack, when you say
           | many apps don't need Auth0 what is the actual alternative for
           | the whole user authentication story?
        
             | zaphar wrote:
             | Most web frameworks come with out of the box authentication
             | plugins that will use your own database. It's plenty good
             | enough and you still don't have to roll your own. Adding an
             | external service adds complexity that you may not want to
             | pay for later.
        
             | angoragoats wrote:
             | Submit a username and password via a form over https. Your
             | backend hashes the password, and checks it against the
             | stored (hashed) password in your database. If it matches,
             | the user provided the correct password. Create a session
             | token (random string is fine) and return it to the user via
             | a cookie in the reply. Store the session token in your
             | database, such that you can map it to the authenticated
             | user. Then on each subsequent request, look up the session
             | token and you have your logged in user.
             | 
             | This is how apps were doing it for literally decades,
             | before JWT was invented. And most web frameworks will do
             | all of this for you.
        
               | swiftcoder wrote:
               | > the stored (hashed) password in your database
               | 
               | Hashed _and_ salted
               | 
               | I hope
        
               | angoragoats wrote:
               | Technically yes, of course, but if you're using an
               | algorithm that requires you to manually worry about
               | salting then you're probably doing it wrong. Hence,
               | "hashed" with an algorithm like bcrypt or scrypt is good
               | enough.
        
               | zaphar wrote:
               | There are some subtleties here that are important to
               | know[0]. Which is why I generally advise people to use
               | the framework provided code for this.
               | 
               | 0: Such as use a secure hash like sha256 or blake2
               | instead of md5.
        
               | angoragoats wrote:
               | Yes, though I would recommend something that is resistant
               | to timing attacks such as bcrypt. And this was why I
               | mentioned frameworks in my last sentence. My intention
               | wasn't to give a comprehensive soup to nuts guide for
               | what to do; instead i was giving a high level overview.
        
               | andoando wrote:
               | Auth0 provides a lot more goodies than this though.
               | Password reset, organizations, multiple login flows, etc
        
               | angoragoats wrote:
               | Yes, and most authentication plugins for web frameworks
               | provide the same things.
        
               | koliber wrote:
               | If you write a B2C app, there is a good chance that you
               | might not need Auth0 and the functionality of the
               | authentication, authorization, and account management
               | tools in your framework suffice. If you plan on selling
               | B2B you might need to support SAML and other enterprise
               | federated login mechanisms. There, the scales tip in my
               | book and I would go with Auth0. It's expensive to support
               | SAML in-house.
        
               | angoragoats wrote:
               | There are plenty of ready made SAML libraries out there
               | that should work with whatever web framework you like to
               | use.
        
           | CuriouslyC wrote:
           | Need? Maybe not. But it's a time saver out of the gate.
        
           | swiftcoder wrote:
           | > You probably don't really need Auth0
           | 
           | And there's a good chance you really don't want to pay for
           | Auth0. Their Enterprise tier becomes very _expensive_ as your
           | MAU starts to grow
        
           | ramesh31 wrote:
           | >but then you are offloading all the issues of JWT's to Auth0
           | so in theory, probably not in practice, you don't have to
           | worry about those.
           | 
           | Yeah, exactly. I get to offload everything to Auth0 instead
           | of maintaining a cryptographer on our payroll to reimplement
           | a solved problem. Hand rolled OSS authz/n may work for
           | individual projects, but there's no other reasonable solution
           | in a modern enterprise environment with SSO.
        
         | rendall wrote:
         | Well, I imagine, if we're taking the opinion of the article as
         | fact, Auth0 must be able to scale to enterprise levels, i.e.
         | have so many long-tail accounts that it approaches
         | Facebook/Google scale.
        
         | augunrik wrote:
         | JWTs are best practice for OAuth as it can transport claims.
         | It's up to your application if you continue to use it after the
         | initial flow. You are fine to convert it, but most apps don't
         | as it's easier.
        
         | koliber wrote:
         | JWT is a great way to authenticate the person who is trying to
         | log into your app. Once authenticated, you are free to exchange
         | the JWT token for a sessionid.
        
           | angoragoats wrote:
           | The whole point of the article was that JWT is unnecessary if
           | you're just using it to get a session token. Why not just cut
           | out the middleman?
        
       | endisneigh wrote:
       | Jwts are fine, just use them properly.
        
         | pwpwp wrote:
         | Maybe address any of the issues raised in the post?
        
         | croes wrote:
         | C/C++ is just fine, just use it properly.
        
           | shiandow wrote:
           | Rolling your own crypto is fine, just do it properly.
        
       | gizzlon wrote:
       | You _can_ implement a blocklist of all the revoked JWT and
       | publish it to all servers. The list should be small, because only
       | otherwise valid tokens need to be included. It becomes so much
       | more complicated than a simple check-the-db setup though.
       | 
       | I don't think I would start with JWT if I did this again.
        
         | esafak wrote:
         | what would you do?
        
           | gizzlon wrote:
           | Sessions, like it's 2005 :P See above.
        
         | brabel wrote:
         | You're talking about tokens in general, not just JWT. The only
         | alternative I know to tokens is to query the DB every time (or
         | perhaps use a cache to make the lookup less often, but then you
         | also have to find a way to invalidate the cache - back to
         | square one?).
        
           | gizzlon wrote:
           | > You're talking about tokens in general, not just JWT. Yes,
           | all stateless tokens. But I have never seen an in-house token
           | system that was not using JWT's.
           | 
           | Yes, query the DB or some sort of storage every time. It
           | sounded so clean and nice and fast to just check JWTs without
           | any network calls. But it ended up very messy and
           | complicated. Might still be worth it in some cases, of
           | course, but I would start my next project with random
           | sessions stored in a db or redis or memcache or .. something
           | :)
           | 
           | You can actually do crazy stuff with your sessions as well,
           | to avoid a normal db lookup. But in practice all services I
           | have worked on would/did not suffer noticeably for a fast DB
           | lookup.
        
       | weinzierl wrote:
       | Using JWT from Keycloak just to obtain a session cookie. Is this
       | a common pattern or a smell?
        
         | doctorpangloss wrote:
         | It's a good idea. The article conflates authentication with
         | authorization. Your application can authorize many different
         | ways, most do. You can use your session for authorization -
         | your application can decide what a person can and can't do. But
         | facts about the user's identity never change, like their
         | uniquely generated ID in your database, and that's what gets
         | stored in Keycloak's `sub` field, so it's fine to use that for
         | trading a token for a session cookie. Their password _does_
         | change but that 's Keycloak's job, is to turn passwords into
         | authentication tokens.
         | 
         | The JWT always stores facts about the principal (aka who or
         | what is doing something), and those don't really make sense to
         | revoke or whatever anyway. Stuff that will never change over
         | time. JWTs can optionally store something like a `role` or
         | similar fact that may change over time, specific to your
         | application. Those facts can be used to decide what you can do
         | in your application, that's authorization. We could talk about
         | when and how that should be done, but it would be too nuanced
         | for these evergreen JWT blogposts.
        
           | tptacek wrote:
           | The article isn't talking about authz at all.
        
         | eYrKEC2 wrote:
         | Taking complete systems off the shelf and using them smells a
         | lot like money. If/when your app requires enterprise
         | integration, you'll be fanatically happy that you chose
         | Keycloak over having to implement okta... then ldap... then..
         | Saml... then.. Kerberos... then ldap again with custom
         | mappers..
        
       | davedx wrote:
       | Okay I'll bite...
       | 
       | This post doesn't seem to address microservice architectures at
       | all? For me, this is the primary reason to use JWT's -- so you
       | can pass authentication ("claims", or whatever you want to call
       | them) through your chain of microservice service-to-service
       | calls. If you don't have microservices then there's much less
       | reason to use JWT's.
       | 
       | I'm not saying the article is a strawman exactly, but it does
       | seem to miss the primary use case of JWT's. At least, the way
       | I've used them in anger.
       | 
       | Also, the "JWT's can be insecure if you use the wrong library or
       | configure them incorrectly" argument, while having _some_ points,
       | seems to me more of an argument that you should really do due
       | diligence on any libraries you use for security. The better JWT
       | libraries are not insecure by default.
       | 
       | I wouldn't use JWT's if I were making a monolith, but there are
       | lots of companies who (for better or worse) use microservices.
        
         | doctorpangloss wrote:
         | > so you can pass authentication ("claims", or whatever you
         | want to call them) through your chain of microservice service-
         | to-service calls.
         | 
         | This is a misconception about so called zero trust. You can't
         | "just" pass the same token to someone else. They can use it to
         | impersonate or misuse the token later. While you are going to
         | say that "my microservices will not impersonate users because
         | to each other, they are all _trusted_ ," you have run directly
         | into the difference between trusted and zero trust.
        
           | EthanHeilman wrote:
           | > This is a misconception about so called zero trust. You
           | can't "just" pass the same token to someone else. They can
           | use it to impersonate or misuse the token later.
           | 
           | Put another way, JWTs used as bearer tokens have vulnerable
           | to intra-audience replay attacks.
           | 
           | While this is true for many zero trust architectures, but you
           | don't have to build zero trust architectures this way. Simply
           | have the token commit to a public key of a signing key held
           | by the identity, then you can do Proof-of-Possession and
           | remove these replay attacks. This is the direction zero trust
           | is headed. For instance AWS is slowly moving toward this with
           | sigV4A. Most zero trust solutions aren't there yet.
        
             | doctorpangloss wrote:
             | Well a lot of value in application architectures like this
             | is, I want to give something access to my Google Calendar
             | forever, to schedule tasks and read stuff, expressly
             | without user intervention. Most people want token exchange
             | - that an all-powerful user token gets exchanged for a
             | token with the privileges specific to the service that
             | holds onto it. I don't really want Google or Apple or
             | whoever has, for idiosyncratic reasons, possession of a
             | private key, to sign every request I make to Google
             | Calendar, because they will inevitably revoke it sooner for
             | obnoxious business reasons than any good security reason.
             | And if I give a signing key to the service doing this deed
             | for me, it's kind of redundant to an ordinary exchanged
             | JWT.
             | 
             | Really the ergonomics are why this hasn't been adopted more
             | readily. I wonder why it's possible to have OpenTelemetry
             | inject a header into thousands of different APIs and
             | services for dozens of programming languages, more or less
             | flawlessly. But if I wanted to do this at process
             | boundaries, and the content of my header was the result of
             | a stateless function of the current value of the header
             | (aka token exchange + destination service): you are shit
             | out of luck. Ultimately platform providers like Google,
             | Apple and Meta lose their power when people do this, so I
             | feel like the most sophisticated and cranky agitators are
             | more or less right that the user experience is subordinate
             | to the S&P top 10's bottom line, not real security
             | concerns.
        
               | EthanHeilman wrote:
               | The first case sounds more like a case for OAuth which
               | doesn't have to use JWTs or digital signatures.
               | 
               | > I don't really want Google or Apple or whoever has, for
               | idiosyncratic reasons, possession of a private key, to
               | sign every request I make to Google Calendar, because
               | they will inevitably revoke it sooner for obnoxious
               | business reasons than any good security reason.
               | 
               | Can you provide more context on this? I would assume
               | asymmetric signing keys are less likely to be revoked
               | than say an HMAC key since an HMAC key must be securely
               | stored at both the client and server whereas you can just
               | put a asymmetric signing key in an HSM at the client and
               | be done with it.
        
               | radicalbyte wrote:
               | Which we have in modern computers and mobiles (the EU
               | identity wallet concept is built around them).
        
               | EthanHeilman wrote:
               | I thought the EU wallet was using JWTs that attest to
               | public key. You don't use them as bearer tokens, you use
               | them as certificates and then do verifiable credential
               | presentation via proof of possession and SD-JWTs.
        
             | marcosdumay wrote:
             | Bearer tokens are vulnerable to man-in-the-middle
             | impersonation.
             | 
             | It's right in the name.
             | 
             | Anyway, zero trust architecture are wildly overrated and
             | used in way more places than they should. But the entire
             | thread is correct in that you can't build them with bearer
             | tokens.
        
               | EthanHeilman wrote:
               | Man-in-the-middle impersonation is not the biggest threat
               | because TLS 1.3 does a decent job of protecting the token
               | in transit. The biggest issue is the endpoints:
               | 
               | 1. The client that holds the token can't use an HSM or
               | SSM to protect the token because they need to transmit
               | it. Thus a compromise of the client via an XSS or
               | Malware, results in the token leaking.
               | 
               | 2. The server that receives the token, might be
               | compromised and they can replay the token to other
               | servers or leak it accidentally e.g., with a log file or
               | to an analytics service.
               | 
               | Both of these problems go away if you uses OpenPubkey or
               | Verifiable Credentials with JWTs. The JWT is now a public
               | value, and the client holds a signing key.
               | 
               | 1. The client can protect the signing key with an HSM or
               | SSM (modern web browsers grant javascript access to a
               | SSM).
               | 
               | 2. The server only receives the JWT (now a public value)
               | and a signature specific to that server. They don't have
               | any secrets to protect.
               | 
               | > But the entire thread is correct in that you can't
               | build them with bearer tokens.
               | 
               | You can and people do, but it is far better to use proof
               | of possession JWTs than bearer JWTs. Even better to use
               | JWS instead of JWTs so you can make use of multiple JWS
               | signers (a JWT is a type of JWS, but a JWS with more than
               | one signer can not be a JWT).
        
           | davedx wrote:
           | If someone nefarious steals your <secret something> then yes
           | you have problems, this isn't anything unique to JWTs
        
             | ummonk wrote:
             | It makes a pretty big difference whether you have to send
             | the secret down the wire to prove you possess it (e.g. a
             | JWT, unlike say a private key).
        
           | DaiPlusPlus wrote:
           | The audience and scope claims exist to address that problem.
           | Provided that RPs reject JWTs issued for other audiences than
           | themselves there's no security weakness here.
           | 
           | This is why JWTs are used in OIDC (e.g. "Sign-in with
           | Google": any website can use it, and it doesn't make Google's
           | own security weaker.
           | 
           | I'll concede that small, but important, details like these
           | are not readily understood by those following some tutorial
           | off some coding-camp content-farm (or worse: using a shared-
           | secret for signing tokens instead of asymmetric cryptography,
           | ugh) - and that's also where we see the vulnerabilities.
           | OAuth2+OIDC is very hard to grok.
        
             | rwdf wrote:
             | It's also why we use DPoP for serious stuff.
        
               | dadadad100 wrote:
               | I hadn't heard of DPoP until this mention. Please tell us
               | more. Google tells me it is Demonstrating Proof of
               | Possession, but is it supported by any products?
        
             | chipdart wrote:
             | > The audience and scope claims exist to address that
             | problem. Provided that RPs reject JWTs issued for other
             | audiences than themselves there's no security weakness
             | here.
             | 
             | My interpretation is that the audience and scope claims, as
             | other features like nonce, are in place to prevent tokens
             | from being intercepted and misused, not to facilitate
             | passing tokens around.
        
         | EthanHeilman wrote:
         | > If you don't have microservices then there's much less reason
         | to use JWT's.
         | 
         | Fair point. This post assumes a single database which opaque
         | tokens can be mapped to. That said, a lot of smaller webapps
         | are and should be monoliths.
        
         | johnnyAghands wrote:
         | Yeah I agree, but I think this post is for those cases where
         | this design might be inappropriate, mainly monoliths with
         | single dbs.
         | 
         | I disagree with the whole "you're not Google/FB"/"over arbitary
         | RPS" logic though. If the design makes sense then it makes
         | sense, end of story. Just understand it.. lol
        
         | wg0 wrote:
         | Side question, anyone knows where the phrase "used in anger"
         | comes from? I know it means using something in production but
         | where does it come from?
         | 
         | Is it about battlefield and such?
        
           | louthy wrote:
           | It's military based isn't it? First time you use a weapon "in
           | anger" is to test its effectiveness in real world conflict
        
           | mceachen wrote:
           | I've always heard it as a shorter alternative to "holy hell
           | this tool is horrible but I'm unaware of an alternative, or
           | cannot apply an alternative solution."
        
           | latentsea wrote:
           | I don't think it necessarily means using it in production but
           | rather using it on some non-trivial capacity that exposes you
           | to it's various complexities and nuances such that you have
           | more than just a surface level understanding. That probably
           | coincides with using things in production a lot of the time,
           | but that's not strictly necessary.
        
         | Ozzie_osman wrote:
         | Even with microservices, you still have the invalidation
         | problem. I guess you could use non-Jwt for external auth and
         | jwt between the services, but then you lose the benefit of
         | standardization (and still don't get full zero-trust). Or you
         | could standardize on jwt, but then, invalidation problem again.
        
           | jupp0r wrote:
           | It's pretty rare in practice to be able to make authz
           | decisions solely based on the information in JWT claims.
           | Space in HTTP headers is limited and any moderately complex
           | system will have a separate authz concept anyways that can be
           | used to check for token invalidation.
        
             | hyperadvanced wrote:
             | Exactly. Learned this the hard way. JWT is good for "this
             | token is legit and has XYZ role or group", and letting it
             | go to the next layer. The next layer should do some
             | addition checking that token has legit claims on modifying
             | a resource or taking other actions, however that might be.
        
         | thayne wrote:
         | Same applies to non-micro service architectures.
        
       | EthanHeilman wrote:
       | > By just using a "normal" opaque session token and storing it in
       | the database, the same way Google does with the refresh token,
       | and dropping all jwt authentication token nonsense.
       | 
       | Not only is this true, but most actual deployments of JWTs just
       | have you swap a JWT (ID Token) for a opaque session token.
       | 
       | That said, I really like having a JWT signed by an IDP which
       | states the user's identity because if designed correctly you only
       | need to trust one party IDP. For instance Google (the IDP) is the
       | ideal party to identify a gmail email address since you already
       | have to trust them for this. I created OpenPubkey to leverage
       | JWTs, while minimizing and in some cases removing trust.
       | 
       | OpenPubkey[0, 1] let's you turn JWTs bearer tokens into
       | certificates. This lets you use digital signatures with ephemeral
       | secrets.
       | 
       | [0]: https://github.com/openpubkey/openpubkey [1]:
       | https://eprint.iacr.org/2023/296
        
       | tobystic wrote:
       | Isn't JWT plaintext? Just remember your security controls
       | 
       | https://owasp.org/www-chapter-vancouver/assets/presentations...
        
         | ozim wrote:
         | I still can put JWT in http only secure cookie.
        
       | jameshart wrote:
       | Browser sessions are not the only authentication scenario.
       | 
       | > absolutely no one who is not Google/Facebook needs to put up
       | with the ensuing tradeoffs. If you process less than 10k requests
       | per second, you're not Google nor are you Facebook
       | 
       | What's the magic property that flips when you pass 10K requests
       | per second? Are we sure it's at 10K requests per second, not 8K?
       | or 5K? In general, at that kind of scale I'd think JWTs would
       | become less appealing - AWS operates on IAM for example.
       | 
       | And why are Google and Facebook the best examples of companies
       | who are operating at scale? There are different kinds of scale
       | than just 'ad auctions per second'. I would imagine the access
       | management concerns of, say, JP Morgan Chase are at least as
       | complex and challenging to scale as those of Facebook.
        
         | EthanHeilman wrote:
         | I once operated a very low usage webservice that used JWT for
         | auth. We got hit with a DDoS and it was trivial to mitigate by
         | using AWS API gateway to drop HTTP requests that didn't contain
         | a valid JWT for the IDPs we supported.
         | 
         | Making authentication only require a signature verification at
         | the edge (JWT) vs authentication middleware that needs to do a
         | DB read (opaque), can be a life saver even if you have 10
         | requests a second most of the time.
        
           | etothepii wrote:
           | This is a great point. 10 requests per second is likely to be
           | sufficient scale that you are noticeable to people that might
           | want to attack you. The ability to validate the key before
           | doing anything with it could be a huge time (and resource)
           | saver on AWS.
        
             | logifail wrote:
             | > The ability to validate the key before doing anything
             | with it [..]
             | 
             | Q: What about the endpoint that's issuing the tokens?
        
               | EthanHeilman wrote:
               | In OpenID Connect the endpoint is issuing the tokens is
               | run by Google, Microsoft or some other company that is
               | too big to fail (or rather if it fails everything goes
               | down).
               | 
               | If you are issuing the tokens yourself, you can build a
               | simple horizontally scaling identity service that only
               | does authentication and token issuance. With refresh
               | tokens, if that service goes down it only prevents users
               | not already signed in from signing in. Generally users
               | stay signed into to webapps for weeks at a time, so you
               | have massively reduced the impact: rather than 100% of
               | your users not being able to do anything on your site,
               | now 0.5% of users are impacted.
        
         | jupp0r wrote:
         | The notion that you have Google/Facebook scale problems at 10k
         | requests per second (vs 10s of millions of requests per second)
         | is a pretty funny claim in its own right.
        
       | conradludgate wrote:
       | A big problem not addressed when not using a signature based
       | authorization scheme is that you need to hit your database for
       | every access attempt. This makes you much more susceptible to
       | ddos attacks.
       | 
       | You need to be able to turn away malicious users as fast as
       | possible. If you take the time to check a database first, that's
       | a precious resource they can consume.
       | 
       | "Add a cache!", you might say? What if they use random client id
       | and client secret for every request, how do you cache against
       | that?
        
         | candiddevmike wrote:
         | The client ID should be a primary key or some other indexed
         | value, making those database hits fairly cheap. You'd also
         | typically have some kind of rate limiting.
        
         | Y-bar wrote:
         | We use a rate-limiting rule in the existing firewall on the
         | /auth endpoint. Our default is on five failed attempts in a
         | five minute window gets you a one hour ban.
        
           | dclowd9901 wrote:
           | How do you fingerprint the requests? IP address?
        
             | tebbers wrote:
             | The problem I had with IP address fingerprints is that we
             | have a large number of customers all behind one hospital's
             | single IP address.
        
             | Y-bar wrote:
             | Two ways, default key is [IP address + User ID] we also
             | have a fallback with a higher limit on [IP address] only
             | when we expect lots of attempts from e.g. a VPN.
        
         | dncornholio wrote:
         | How do you think people make applications if every database
         | call is suspectible to ddos?
        
           | EthanHeilman wrote:
           | 1. Authenticate using signed JWTs at the edge via something
           | like AWS API Gateway. 2. If the attacker is smart enough to
           | use valid JWTs from IDPs. Find the JWTs that match the DDoS
           | attack and ban those identities at the edge. This rate limits
           | the attacker to how quickly they can generate new accounts on
           | say gmail or azure. 3. If the attacker is can generate new
           | accounts fast enough, add a bloom filter to the edge of
           | accounts you have seen before the attack started.
           | 
           | At some point the attacker either gives us or just switches
           | to the brute force of flooding the pipes with so much traffic
           | that the AS doing the filtering goes down. At that point it
           | is now someone else's problem. They might start de-peering
           | the ASes generating the traffic.
        
         | tptacek wrote:
         | The article talks about when and how requests hit the database
         | in _both_ schemes, extensively.
        
       | 5cott0 wrote:
       | fine with me as long as you don't pronounce it "jay double-u tee"
        
         | chrisweekly wrote:
         | ok I'll bite; how do you pronounce it?
        
           | selectnull wrote:
           | jot
           | 
           | https://datatracker.ietf.org/doc/html/rfc7519#section-1
        
             | chrisweekly wrote:
             | Awesome, thank you!
             | 
             | > The suggested pronunciation of JWT is the same as the
             | English word "jot".
             | 
             | 1 syllable instead of 5 FTW
        
       | rendall wrote:
       | While I could agree with the sentiment "consider using opaque
       | auth tokens instead of JWTs in most use cases" I can't get behind
       | the opinion-presented-as-factual-statement tone of the article.
       | There are valid use cases to offload authentication to the client
       | rather than verifying an opaque token with every request. One
       | advantage is that community support for JWTs is large, but home-
       | grown, ad-hoc opaque token solutions not so much. Another is that
       | any claim at all can be stored in the JWT: IP address, user name,
       | opaque token, whatever makes your app secure. While these same
       | claims _could_ be stored in a database, now you have extra
       | overhead and maintenance dealing with them.
       | 
       | I would like to see an open-source project from this author that
       | uses his proposed solution.
        
         | angoragoats wrote:
         | IMHO the stateful opaque token approach is simple enough that
         | it can (and often does) get baked into whatever
         | language/framework you're using to write your app. In addition,
         | the very nature of session tokens is such that the logic for
         | what the token actually means/represents lives in your app, on
         | the server.
         | 
         | So, that may be why we don't see more "opaque session token"
         | standards/libraries out there as an alternative to JWTs.
         | 
         | But if you want an existing example, Devise for Rails [1] has
         | been around a while.
         | 
         | [1] https://github.com/heartcombo/devise
        
       | bebop wrote:
       | I would add two pros of jwts (I guess oauth 2 and oidc more
       | specifically)
       | 
       | 1. It standardizes your auth system. While sessions auth is
       | mostly implemented in the same way across systems, learning oauth
       | and oidc gives you a standard across the industry.
       | 
       | 2. Jwts give an easy path to make "front end" applications and
       | api authentication work in the same way. This in theory reduces
       | your security surface area as all of your authnz code can be
       | shared across your offerings.
        
         | andoando wrote:
         | 3. Easy to implement. 4. Dont need to hit db. 5. Can store some
         | information with the claim which is very convenient
        
           | pests wrote:
           | How do you revoke tokens if a one gets leaked without hitting
           | a db? How long are your users vulnerable to attack?
        
             | moomoo11 wrote:
             | Use low TTL and put rate limits and other mechanisms in
             | place?
        
               | jjice wrote:
               | I think you're right, but it seems like you get into a
               | tricky territory that'll never be great (as everything
               | with security has compromised). Too long is an issue for
               | attacks, but convenient for users. Too short and you have
               | to do an initial re-auth over and over again, partially
               | defeating the benefits.
               | 
               | Even if the TTL is short, there are plenty of ways to
               | compromise a token and use it immediately in an automated
               | system.
               | 
               | If you're using JWTs, I'd lean shorter TTLs and embrace
               | this as a potential concern. Not sure what the best re-
               | auth frequency is though. I'd be really interested to see
               | other's thoughts on that.
        
               | moomoo11 wrote:
               | But the token is used over SSL and the only way to get it
               | afaik is to hijack the client device or somehow hijack
               | the server. The first scenario is pretty rare and the
               | second is pretty easy to avoid. I don't think that's
               | really an edge case that's concerning for 99% of
               | applications.
        
             | bebop wrote:
             | Yes, this is the trade off. If you are working in an
             | industry where you need to be highly sensitive for data
             | access even for short periods of times then oauth/oidc/jwts
             | are probably not for you. If you really need an emergency
             | escape hatch you can always rotate your singing keys and
             | jwks and invalidate all of your tokens and force everyone
             | to sign back in.
        
             | andoando wrote:
             | Good point.
             | 
             | If a short session time isnt good enough, you can use a
             | simple key store to check for revoked tokens. Youll be
             | hitting a db but its somewhat better since its just a very
             | small db of revoked tokens.
             | 
             | Its hard for me to imagine though with like a 30 min or
             | even few hour long token, under what circumstances you'd
             | actually revoke tokens. If your db got leaked, you can
             | rotate the key and invalidate all tokens. Otherwise, itd
             | have to be something like you have some post login fraud
             | detection in place. Cause jwt or not, if a user just signed
             | in and a hacker got their auth token, what are you going to
             | do? Sure you need to check the db to revoke it, but the
             | problem is how would you know the tokens been compromised?
        
             | xorcist wrote:
             | Another way to put it: "Do you want a (functional) logout
             | button?"
        
               | tasuki wrote:
               | That's not another way to put it. You can have a logout
               | button which makes the client forget the jwt token.
        
               | sweetjuly wrote:
               | Why would you need to revoke on logout? Forgetting seems
               | to be enough in all cases except maybe SSO revocation
               | because in all other cases you can (and indeed often
               | must) trust the client to protect the credential.
        
             | beeboobaa3 wrote:
             | Store reset_time per user. Use a message queue (or postgres
             | notify) to _push_ changes to this value to your apps. Check
             | the user 's token was created after the reset_time when
             | validating it.
             | 
             | You would be required to keep a Map<UserId, Timestamp> in
             | memory, potentially with TTL. Most systems can handle this
             | easily for their expected user load. If not, you should
             | have the engineering capacity to figure it out ;)
             | 
             | Logout button sets reset_time to now, as does revoking
             | tokens. This would only allow you to revoke all tokens for
             | one user at the same time, but this tends to be fine, since
             | JWTs should be short-lived anyway and apps should deal with
             | the expectation of them being expired/revoked.
        
               | nosefrog wrote:
               | And hope your service hasn't been restarted so it doesn't
               | lose the in-memory revocation list?
        
               | beeboobaa3 wrote:
               | Just populate the cache when you need it? You will need a
               | database round trip for the first request per user per
               | application restart, if they haven't reset since. I
               | assumed this was obvious.
        
               | nosefrog wrote:
               | Oh, I didn't realize that the design also has a database
               | of revocations. In that case, you can just query that
               | directly :P
        
               | beeboobaa3 wrote:
               | You'll want to store your user credentials that they
               | traded for a JWT somewhere. The point of using JWTs is
               | that most of your requests don't have to hit this
               | database.
        
             | zdragnar wrote:
             | You can use a separate DB that acts more like a cache for
             | revocations- usually something where you can set a time to
             | live on the row equal to the duration of the token itself.
             | 
             | That keeps your application DB free for application load,
             | while keeping your identity validation logic nice and
             | snappy.
             | 
             | Of course, adding infrastructure may be intimidating, but
             | most applications that face any real load are going to be
             | using redis or something similar anyway at some place in
             | the stack.
        
               | akerl_ wrote:
               | If I have to run a separate DB to check for revocations,
               | why not skip JWTs and just use that separate DB for auth
               | directly.
        
               | andoando wrote:
               | Not an issue for most cases but a cache of revoked tokens
               | is going to be much smaller than a db of all users
               | tokens.
        
       | adeptima wrote:
       | JWT is not a protocol but kind of a message format from my
       | perspective.
       | 
       | https://www.rfc-editor.org/rfc/rfc7519
       | 
       | It can be signed with HMAC SHA-256 algorithm: {"typ":"JWT",
       | "alg":"HS256"}
       | 
       | Ripping off JWT from surrounding context is a road to hell.
       | 
       | It's worth to study JWT in context of OIDC (OpenID Connect) IDP
       | providers.
       | 
       | You will quickly bump into buzzwords like client (RP), server
       | (OP), PKCE, Token Exchange, mTLS and all kind of Implicit. Hybrid
       | flows.
       | 
       | My biggest regret I didn't go through JWT related RFCs and OpenID
       | Connect specs earlier.
       | 
       | [1]: https://openid.net/specs/openid-connect-
       | core-1_0.html#CodeFl... 3.1. Authentication using the
       | Authorization Code Flow
       | 
       | [2]: https://openid.net/specs/openid-connect-
       | core-1_0.html#Implic... 3.2. Authentication using the Implicit
       | Flow
       | 
       | [3]: https://openid.net/specs/openid-connect-
       | core-1_0.html#Hybrid... 3.3. Authentication using the Hybrid Flow
       | 
       | [4]: https://openid.net/specs/openid-connect-
       | core-1_0.html#Client... 9. Client Authentication
       | 
       | [5]: https://openid.net/specs/openid-connect-
       | core-1_0.html#Refres... 12. Using Refresh Tokens
       | 
       | [6]: https://openid.net/specs/openid-connect-discovery-1_0.html
       | OpenID Connect Discovery 1.0 incorporating errata set 1
       | 
       | [7]: https://www.rfc-editor.org/rfc/rfc7523.html JSON Web Token
       | (JWT) Profile for OAuth 2.0 Client Authentication and
       | Authorization Grants
       | 
       | [8]: https://www.rfc-editor.org/rfc/rfc7636.html Proof Key for
       | Code Exchange by OAuth Public Clients
       | 
       | [9]: https://www.rfc-editor.org/rfc/rfc8693.html OAuth 2.0 Token
       | Exchange
       | 
       | [10]: https://www.rfc-editor.org/rfc/rfc8628.html OAuth 2.0
       | Device Authorization Grant
       | 
       | [11]: https://www.rfc-editor.org/rfc/rfc8705.html OAuth 2.0
       | Mutual-TLS Client Authentication and Certificate-Bound Access
       | Tokens"
       | 
       | If you dont have patience for RFCs and specs, just go play with
       | open sources IDP or better start from OpenID Connect client and
       | server library, and try to integrate it into your "hellohell" app
       | ;)
       | 
       | Very soon you will find out why developers keep building their
       | own IDPs and how simple OpenID Connect can become a full time
       | business
       | 
       | Go back here and here
       | http://cryto.net/~joepie91/blog/2016/06/19/stop-using-jwt-fo...
       | 
       | And reflect yourself
       | 
       | Trust nobody
        
       | rblatz wrote:
       | Oh man, he goes straight to stateful services as an alternative
       | to JWTs. What an absolute nightmare, if JWTs are too hard
       | stateful services are certainly more difficult.
        
         | tptacek wrote:
         | Stateful services meaning the default way every web framework
         | has structured a web application since 2005?
        
           | vundercind wrote:
           | Longer, if we allow "web application" to mean "anything with
           | a login, on the web". All those popular forums, likely also
           | stuff like yahoo mail, even gaming services (yes, browser-
           | based game matchmaking services existed in the 90s, Microsoft
           | ran one, among others) probably just because anything else
           | would have been needlessly complicated and expensive.
        
       | lvlabguy wrote:
       | You should not use JWT if you have a single application in your
       | organization. However, whenever you have multiple applications,
       | you need some form of central authentication / authorization
       | service. Otherwise, you would have to maintain auth databases in
       | each application, each application will need to be logged-in
       | separately, you won't be able to implement a simple "suspend a
       | user's accounts after X unsuccessful auth attempt", you won't
       | have a central auth log.
        
       | zemo wrote:
       | External services use jwts pretty often, so if you have to handle
       | jwts anyway, using jwts means that there's only one primitive,
       | set of libraries, and concepts for your devs to know.
       | 
       | "You don't need all of that!" sure but you probably already
       | _have_ it somewhere in your codebase and it 's pretty universal.
       | You also probably don't utilize every feature of http itself,
       | that isn't a cogent argument against using http.
       | 
       | JWTs are supported by a large number of tools, libraries,
       | middleware appliances, etc; there's a huge ecosystem out there to
       | support it.
       | 
       | You also might delegate auth to a third party like Auth0 or
       | FusionAuth so that you don't handle _any_ PII, because all of the
       | PII is handled by a vendor, and you only store application-
       | specific data.
       | 
       | "You want to implement logout" means a few things; in most apps
       | you just ... have the client forget the token and you go about
       | your day and it's fine. "but what about if a nefarious actor
       | stole the token!!!" you might say, but hand-rolled session tokens
       | have the same problem.
       | 
       | "You want to turn off access for all users" is something you can
       | do in http middleware; e.g., I have used middleware that do
       | things like "only allow through requests that have jwts with the
       | 'admin' role in their claims because we have turned off the
       | system from users for downtime", and that works fine.
       | (specifically I wrote a traefik plugin to do this in an
       | afternoon).
       | 
       | "You want to ban a single specific user really quickly" is a
       | thing JWT won't do out of box.
        
         | tptacek wrote:
         | The problem isn't the mechanisms inside of JWT (though they are
         | gross and worth avoiding on their own), it's the systems-level
         | tradeoffs you have to make to use them idiomatically,
         | particularly around refresh tokens and revocation.
         | 
         | If you read this and think "this doesn't apply as long as I
         | have to use JWTs for some service I rely on, anyways", you
         | missed its point.
        
           | zemo wrote:
           | refreshing the refresh token is always a database hit, and in
           | the case of using a third party like Auth0 or FusionAuth, you
           | can invalidate refresh tokens at the individual and at the
           | user level. Saying "the refresh token is the real token" as
           | the article does is pretty misleading; the refresh token
           | always goes to the same system that would accept the
           | username/password, but the jwt itself gets carted around to
           | other systems. So again, in the auth0/fusionauth case, the
           | refresh token is sent to auth0/fusionauth, not your app, so
           | even without any particular knowledge of what's going on, the
           | application developer is forced to utilize them in different
           | ways. There's a big assumption in this article that you're
           | talking about a monolithic system where logins are processed
           | by the same application that handles all requests. Even if
           | you _do_ prefer to structure your application as a monolith
           | and avoid microservices, once you delegate auth to a third
           | party or a system separate from your app, the bearer token
           | versus refresh token thing starts to matter a _lot_.
           | 
           | I think there's a cyclic thing that's been happening for
           | _years_ where people in the security community like to talk
           | about how bad jwt is, but then not produce anything that
           | meets application developers needs in a meaningful way. I
           | spent _years_ avoiding jwt and ultimately found avoiding jwts
           | wasn 't actually a good use of my time.
        
             | tptacek wrote:
             | This still doesn't engage with the point. "Refresh tokens"
             | are not a natural feature of every session scheme. They're
             | required by stateless JWTs because JWTs are motivated by
             | migrating authN into its own independently-scaled
             | microservice, and because online revocation is difficult in
             | stateless schemes. If you just use your framework session
             | system, you don't ever think about refresh tokens. That's
             | the point the article is making. It's not that JWT makes
             | refresh harder, it's that it makes it a thing at all.
        
               | zemo wrote:
               | right so then the argument is less about "should you use
               | JWTs" and more about "should you use stateless session
               | tokens".
               | 
               | > JWTs are motivated by migrating authN into its own
               | independently-scaled microservice
               | 
               | that's definitely one use-case, although I don't actually
               | think having auth in a separate microservice under your
               | own custody is the dominant use-case. The auth being in
               | an entirely separate database means _PII_ is in an
               | entirely separate database, which can be a useful access
               | control mechanism, or in the case of using a third-party
               | auth service, means that _there is no PII in databases
               | under your custody at all_. It makes the situation of
               | "developers can access all data created by the software
               | that they work on" really easy to implement while also
               | maintaining "developers do _not_ have access to all of
               | the PII " as an access barrier. I think "I just use
               | Auth0/FusionAuth and don't think about it" is actually
               | the dominant use-case, and every third party offering
               | that kind of developer experience utilizes stateless
               | session tokens to make that happen.
               | 
               | > If you just use your framework session system, you
               | don't ever think about refresh tokens.
               | 
               | right, but now the problem of keeping PII data access
               | rules separate from your application domain data is an
               | additional thing you have to engineer and think about
               | securing, so I think the article is underestimating some
               | of the negatives of that tradeoff; I've never seen a
               | framework with a built in session system that did a good
               | job of keeping access to the PII separate from the
               | application data.
        
               | tptacek wrote:
               | You wrote a comment upthread that misapprehended the post
               | you were critiquing. I was motivated to offer some
               | corrections. I'm less interested in the philosophical
               | argument you now propose, except to say that PII
               | segregation has only very rarely been the reason I've
               | seen people adopt stateless tokens. It is _still_ easier
               | to segregate data using stateful token schemes than with
               | JWT.
               | 
               | But I don't want to pretend we're still having the same
               | conversation that started up thread. I assume you take my
               | point, that if you think "I already have to do JWT so I
               | don't save anything by not using them everywhere" rebuts
               | the post, you've misread it a bit.
        
               | zemo wrote:
               | > if you think "I already have to do JWT so I don't save
               | anything by not using them everywhere" rebuts the post
               | 
               | I have never believed that and I don't think my comment
               | ever suggested I did, I mentioned "you might have jwt-
               | handling tooling already" as one concern among many, not
               | an entire argument. It really seems like you've honed in
               | on a single point and, as you would say, misapprehended
               | my comment. That one argument is not reason alone to use
               | JWT and I really don't think my original comment ever
               | implied I thought it was the entirety of the topic.
        
             | jupp0r wrote:
             | My impression is that the article author is following the
             | good old "everything lives in my Rails monolith" philosophy
             | from 10 years ago where login and authn is just another
             | library including db migrations that you slap onto your
             | monolith to get user management set up in 15 minutes.
        
               | zemo wrote:
               | in all fairness that's what 95% of web application
               | projects really should be.
        
               | jupp0r wrote:
               | 70% of the web is Wordpress, so yeah.
        
           | notnullorvoid wrote:
           | Having authn stateless whether with JWTs or not is a bad
           | idea. By extension refresh tokens are a bad idea. Doesn't
           | mean JWTs are a bad idea, if used as a general auth token
           | they are fine. Implementing revocation of JWTs also isn't
           | very hard but you need somewhere to store the revocation
           | state.
        
             | tptacek wrote:
             | Sorry, none of this is responsive to what I just wrote. I
             | had a particular complaint about the critique I responded
             | to, that's all.
        
       | firefoxd wrote:
       | Some people made the distinction here, jwt on the front end vs
       | the micro services across the network.
       | 
       | I've experienced more than once, issues where the auth service
       | has bugs and the logged out session is still valid for a long
       | time. Or an attacker that figured out the micro services
       | blueprint and now had authed access to the entire network.
       | 
       | Jwt is still useful between services, however the front end can
       | do just fine with a session id that can be easily revoked.
        
       | Galanwe wrote:
       | The article misses the point of JWT: it's dead simple to
       | implement.
       | 
       | I don't implement JWT because I fancy big data terascale
       | technologies. I do it because it's mostly stateless, meaning it's
       | very easy to mock locally, and easy to deploy.
       | 
       | > You wanted to implement log-out, so now you're keeping an
       | allowlist of valid JWTs, or a denylist of revoked JWTs. To check
       | this you hit the database on each request.
       | 
       | No, you just remove the JWT from the local storage. Sure, the
       | user could then relogin if he copied it, but if it's on his own
       | will, why not. And if he got his JWT stolen before logout, bah
       | anyway any token could have been stolen that way, whatever the
       | tech.
       | 
       | > You need to be able to block users entirely, so you check a
       | "user active" flag in the database. You hit the database on each
       | request.
       | 
       | Right but that contradicts the whole premise of the article,
       | being that you probably don't need fancy features. 99.9% of
       | websites don't need to ban users _instantly_. If you have a fair
       | JWT expiration, it's usually OK.
       | 
       | I'd argue for the exact opposite of the article. If you want dead
       | simple Auth, without fancy tech, just use JWT.
        
         | CiPHPerCoder wrote:
         | > The article misses the point of JWT: it's dead simple to
         | implement.
         | 
         | Implementing it _securely_ , however, is far from dead simple.
         | 
         | https://scottarc.blog/2023/09/06/how-to-write-a-secure-jwt-l...
        
         | pjerem wrote:
         | > And if he got his JWT stolen before logout, bah anyway any
         | token could have been stolen that way, whatever the tech.
         | 
         | The thing is, with the good old "token in the database" method,
         | logging out means deleting the token from the database so no,
         | you can't reuse a stolen token after a logout.
        
           | gkbrk wrote:
           | If the user can somehow get their token stolen from the
           | browser, they can also get their username/password stolen
           | from the browser.
        
             | sweetjuly wrote:
             | Plus, a compromised browser could just block the logout
             | request. It's a nonsense and indefensible threat model. If
             | you need to worry about compromised browsers, you need a
             | mitigation which doesn't rely on the browser or that'd be
             | easily compromised by someone who could compromise the
             | browser.
             | 
             | It's a slightly different story with a "logout all
             | sessions" button where the user might press it from a
             | trusted device, but that's a different functionality than a
             | logout button. There you would need revocation, but if you
             | (like many websites) don't actually support this
             | functionality you really don't even need to support a
             | logout functionality more complex than just asking the
             | client nicely to please delete the token.
        
         | adhamsalama wrote:
         | What if you want to implement logging out all user sessions?
         | 
         | You'd have to store something somewhere, so you end up losing
         | the benefits of stateless authentication.
        
           | dudus wrote:
           | That's a fancy feature. The article is all about sticking to
           | what is simple and without fancy features
        
       | menthe wrote:
       | Everyone's talking about how you MUST hit the database for
       | revocations / invalidations, and how it may defeat the purpose.
       | 
       | How is no one thinking of a mere pub-sub topic? Set the TTL on
       | the topic to whatever your max JWT TTL is, make your applications
       | subscribe to the beginning of the topic upon startup, problem
       | solved.
       | 
       | You need to load up the certificates from configuration to verify
       | the signatures anyways, it doesn't cost any more to load up a
       | Kafka consumer writing to a tiny map.
        
         | akerl_ wrote:
         | So, basically a database where you store a replica in memory on
         | every edge node.
        
         | marcosdumay wrote:
         | For maximum scalability you'd want a bloom filter at each
         | service for testing the token, and some central revocation
         | lists where you go test the token that fail this.
         | 
         | But this is way overkill for anybody that isn't FAANG, and it's
         | probably overkill for most of FAANG too. On normal usage, it's
         | standard to keep the revocation filter centralized at the same
         | place than handles renewals and the first authentication. This
         | is already overkill for most people, but it's what comes pre-
         | packaged.
        
       | meling wrote:
       | A former student of mine (Vera Yaseneva) redesigned our old auth
       | architecture using jwts and I'm pretty happy with how it turned
       | out. Maybe it is overkill for our simple autograder server, but
       | it was fun getting it to work and I'm sure it is more secure than
       | the old architecture which had many many flaws... it was a
       | maintenance nightmare for years. After the redesign it has been a
       | breeze. Here is the project
       | https://github.com/quickfeed/quickfeed
       | 
       | The security arch is mainly in web/auth and web/interceptor
       | packages if anyone is interested in learning from the code. It
       | uses connectrpc, which has a nice interceptor arch.
       | 
       | Happy to share Vera's thesis report if anyone is interested...
        
         | hu3 wrote:
         | Thank you for sharing! I took a look at the code. Looks clean.
         | 
         | Please share her thesis. I'm interested.
        
       | phendrenad2 wrote:
       | I'm thankful every day I don't have to work on a team where JWTs
       | are a valid solution, and nobody suggests them regardless. What a
       | nightmare.
        
       | dathinab wrote:
       | It's the wrong question.
       | 
       | It's like asking what language should I use for programming a
       | game? A common question, but of which the answer isn't a language
       | choice. Instead it is that you approach the problem from the
       | wrong direction.
       | 
       | The more useful question is what framework/service/library do I
       | use for handling that, and then you use whatever it uses. Which
       | most times means use whatever your web framework provides (as the
       | blog author concluded).
       | 
       | The next question is what do you concretely hope to get from
       | doing so and are there easier ways to get it (likely yes, and not
       | some vague "but statles is better argument").
       | 
       | Then ask yourself how do you handle revocation? A question which
       | is essential when using JWT and other stateless auth tokens (a
       | answer of idk./I will think later about don't count. I don't can
       | be a valid answer, but only very very rarely).
       | 
       | I think it's not an understatement to say that the huge majority
       | of custom JWT usage falls under harmful premature optimization.
       | 
       | I wrote "custom" because sometimes you don't have a choice, e.g.
       | you need to use OIDC for social login as the main form of AuthN &
       | AuthZ and then already have some service (not just library) which
       | fully handles OIDC/JWT including revocation for you (i.e. you
       | don't validate the JWT stateless but ask the service every time).
       | Through that approach (especially the later part) can have
       | scaling limits but, eh, we are back at premature optimization ;)
        
       | bakugo wrote:
       | The beauty of JWTs is that, if you have to ask "do I need JWTs?",
       | you probably don't need JWTs.
        
       | jonplackett wrote:
       | I'd like to hear a reply from someone at Supabase
        
       | Aldipower wrote:
       | Fair enough, access token/refresh token pairs all have those
       | issues described in the article. But why hating against JWTs
       | (pronounced 'JOT' btw) in general? There are other stateless
       | techniques making use of a JWT, which are very easy and secure to
       | implement. For examples the single auth token approach, with
       | maybe a 2 days expiry and a renew window if the user is active.
       | For some scenarios this is perfectly fine, it is stateless and
       | has no refresh token. User logs out by just deleting the token
       | client side.
        
         | oxidant wrote:
         | Not saying you're wrong about the pronunciation, but "jot" is
         | the suggested pronunciation, not the required one [0]. I used
         | "jay double-you tee" for a long time and it doesn't bother me
         | how people pronounce it.
         | 
         | [0] https://datatracker.ietf.org/doc/html/rfc7519#section-1
        
       | jupp0r wrote:
       | "Just use the normal session mechanism that comes with your web
       | framework and that you were using before someone told you that
       | Google uses jwt. It has stood the test of time and is probably
       | fine."
       | 
       | You don't need to be Facebook or Google to have more than one
       | service in your infrastructure that needs to authenticate a
       | user's existing session without forcing the user to log in again.
       | Sharing the session across multiple services is its own
       | distributed systems problem with numerous security implications
       | to be aware of and bearer tokens might be a good alternative.
       | 
       | If all you have is a single monolith web app that is the identity
       | provider, makes all authentication decisions etc then yes, you
       | don't need JWTs probably. There is a huge gap between that and
       | being Google/Facebook.
       | 
       | Apart from that, Google and Facebook don't even use JWTs between
       | the browser and backends after the initial login but actually do
       | have some sort of distributed session concept last time I
       | checked.
        
         | _heimdall wrote:
         | This is a perfect example of "it depends" being the right
         | answer.
         | 
         | Should a project use sessions or JWTs? One isn't right or
         | wrong, it all depends on the context of the project.
        
         | Aurornis wrote:
         | > You don't need to be Facebook or Google to have more than one
         | service in your infrastructure that needs to authenticate a
         | user's existing session without forcing the user to log in
         | again.
         | 
         | Thank you. This middle ground between hyperscaler
         | infrastructure and super simple web apps is where most of my
         | career has been spent, yet the recent trend is to pretend like
         | there are only two possible extremes: You're either Facebook or
         | you're not doing anything complicated.
         | 
         | It has an unfortunate second order effect of convincing people
         | that as soon as they encounter something more complicated than
         | a simple web app, they need to adopt everything the
         | hyperscalers do to solve it.
         | 
         | I wish we could spend more time discussing the middle ground
         | rather than pretending it's some sort of war between super
         | simple or ultra complex.
        
           | rescbr wrote:
           | Specially since the middle is way larger than people think.
        
           | kelnos wrote:
           | I still don't think people in the middle need JWTs.
           | 
           | If we're talking about a web session, time-limited randomly-
           | generated session tokens that are stored in a DB still work
           | fine. If you really need it, put a caching layer (memcached
           | or redis or valkey or whatever) in front of it. Yes, then
           | you've created cache invalidation problems for yourself, but
           | it's still less annoying than JWT.
           | 
           | If we're talking about authenticating API requests, long-
           | lived randomly-generated auth tokens stored in a database
           | work fine, generally. (But allow your users to create more
           | than one, and make rotation and revocation easy. Depending on
           | your application, allowing your users to scope the tokens can
           | also be a good thing to do.) Again, put a caching layer in
           | front of your database once you get to the scale where you
           | need it. You probably won't need it for a while if you're
           | sending your reads to read-only replicas.
           | 
           | (Source: worked at Twilio for 10 years; we definitely
           | eventually ran into scaling problems around our user/auth DB,
           | and our initial one-auth-token-is-all-you-need setup was
           | terrible for users, but these problems were fixed over time.
           | Twilio does use JWTs for some things, but IMO that was
           | unnecessary, and they created more headaches than they
           | solved.)
           | 
           | I'm not saying no one ever needs JWTs, but I think they're
           | needed in far fewer circumstances than most people think,
           | even people who agree that JWTs should be looked upon with
           | some skepticism. If you need to be able to log people out or
           | invalidate sessions or disable accounts, then JWTs are going
           | to create problems that are annoying to solve.
           | 
           | (One possibly-interesting solution for JWT-using systems that
           | I haven't tried anywhere is to do the reverse: don't cache
           | your user/auth database, but have a distributed cache of JWTs
           | that have been revoked. The nice thing about JWTs is that
           | they expire, so you can sweep your cache and drop tokens that
           | have expired every night or whenever. Not sure how well this
           | would work in practice, but maybe it's effective. One big
           | problem is that now your caching layer needs to be fail-
           | closed, whereas in a system where you're caching your
           | user/auth DB, a caching layer failure can fall back to the
           | user/auth DB... though that may melt it, of course. I also
           | feel like it's easier to write logic bugs around "if this
           | record is not found, allow" rather than "if this record is
           | not found, deny".)
        
             | crabmusket wrote:
             | > But allow your users to create more than one, and make
             | rotation and revocation easy
             | 
             | It's shocking how often this advice isn't followed. We
             | often see it with non-tech companies who nonetheless
             | deliver services over the internet.
        
             | MrDarcy wrote:
             | > If we're talking about a web session, time-limited
             | randomly-generated session tokens that are stored in a DB
             | still work fine
             | 
             | This works fine for a single service but you're replying to
             | a thread about the middle ground of multiple services. It's
             | an anti pattern to have every service talk to the same
             | database just to authenticate every request.
             | 
             | By the time you add a caching layer you're truly better off
             | using an off the shelf oidc id provider and validating the
             | id token claims.
        
             | jupp0r wrote:
             | "have a distributed cache of JWTs that have been revoked.
             | The nice thing about JWTs is that they expire, so you can
             | sweep your cache and drop tokens that have expired every
             | night or whenever."
             | 
             | Every cache has TTL, so you just set the TTL of the entry
             | to the expiration date of the token you are caching. No
             | need for nightly cleanups.
        
             | jupp0r wrote:
             | "If we're talking about a web session, time-limited
             | randomly-generated session tokens that are stored in a DB
             | still work fine. If you really need it, put a caching layer
             | (memcached or redis or valkey or whatever) in front of it.
             | Yes, then you've created cache invalidation problems for
             | yourself, but it's still less annoying than JWT."
             | 
             | You just (somewhat handwavingly) described what Google and
             | Facebook are doing. You might not need to build this
             | globally highly available distributed session store, JWTs
             | might be an ok solution for your use case too (because you
             | are not Google or Facebook) - or not. It depends on what
             | your requirements are. AuthN across services is somewhat
             | complex in any case, I don't think there is an easy way
             | around it without making tradeoffs somewhere. JWTs are a
             | great tool to consider here.
        
           | turtlebits wrote:
           | It's not a trend. Those on the extreme ends of the spectrum
           | are always the most vocal.
        
       | dudeinjapan wrote:
       | At TableCheck we use JWTs to enable user logins across several
       | sub-apps, using an auth service we built in-house using Elixir.
       | 
       | It's a well-documented standard and we've never had an issue with
       | them since launching.
       | 
       | The supposed drawback that sessions must live for X minutes, is
       | just not a problem in practice.
        
       | tzahifadida wrote:
       | Probably a waste of time to answer due to the long thread here.
       | But short answer: you can store tokens in a server session which
       | will manage it for you. In case you need to refresh it, you are
       | redirected to the idp and get a refreshed token which again
       | stored inside the session. So you can handle any "microservice"
       | scenario as was called here, not sure why micro is important...
       | Also, it is a misconseption that the tokens,as it where, are not
       | stored on the oidc providing service. How are you going to logout
       | someone or invalidate or simply track devices? It is going to be
       | stored somewhere and there is nothing wrong with it. It is matter
       | of scale, if you are not facebook the addition is miniscule,
       | especially with distributed cache. Again, a misconseption it is
       | not being used already, e.g. on keycloak if you want HA you have
       | to enable distributed cache. So really naive thinking that
       | session is bad or jwt is bad. They are simply tools used by
       | protocols and the only question is usually what do you prefer
       | unless you get to the edge cases of performance which unless you
       | are facebook, my face would look daughtful to begin with if you
       | raise this argument.
        
         | Arch-TK wrote:
         | It's super common to see websites which don't properly
         | invalidate sessions because they use JWTs without tracking them
         | anywhere.
        
       | YetAnotherNick wrote:
       | > In this setup the refresh token, not the authentication token,
       | is the real session token
       | 
       | Yes, and why is that a problem? It is the best of both worlds as
       | the verification of access token is standardized and fast while
       | refresh token could be used at the first call of the session.
       | Yes, it could happen that the user is logged in for 5 more
       | minutes if the user is in middle of session, but it's really such
       | a edge case which most companies don't need to worry about.
        
       | snowstormsun wrote:
       | One huge benefit of random session tokens is also that you can't
       | include arbitrary metadata that is sent to the client.
       | 
       | Decoding JWTs of web apps can give you a lot of suprises like the
       | account email address or even password being stored inside them.
       | For devs that don't know the difference between signing and
       | encrypting JWTs are a footgun and even for those that do it can
       | be confusing. The specifications are also a hard read. A handful
       | of RFCs where you don't really know which one to lookup. JWT,
       | JWK, JWE, JWA, WTF? It seems to do everything at once, signing
       | and encryption, symmetric and asymmetric, and the format is
       | always quite similar!
       | 
       | On the other side, if you are able to avoid the many pitfalls,
       | JWTs can be very useful in the right place when used properly.
       | You could probably write an equally or more secure JSON based
       | token format from scratch without that much effort by just
       | keeping it simple and restrictive/opinionated, though.
        
         | tored wrote:
         | One huge benefit of using a non-randomized token is that you
         | can verify that you created it.
        
       | therealfiona wrote:
       | Here I was hoping someone was using the James Webb Telescope to
       | do some crazy authentication process that I never could have
       | imagined. Was hoping something like the Cloudflare lava lamp
       | wall, but much slower.
        
       | jurassic wrote:
       | The more confidently people make blanket pronouncements, the less
       | you should believe them. There are a lot of use cases for OAuth2
       | and OIDC that are not covered by "just use a web session".
       | 
       | The real thing to push back on is the logout requirement.
       | Everyone pretends they need this, when what almost everyone
       | should do is just mandate appropriately short token lifetimes and
       | revoke refresh tokens as needed.
        
       | aranchelk wrote:
       | Even running in smaller environments:
       | 
       | 1) You may not want your application servers having direct access
       | to your auth service or auth database. You may not have the
       | resources to control employee access to sensitive data when it's
       | shared across services. You may want to spend limited resources
       | for security audits on the systems that contain the most
       | sensitive data, and having them separated from everything else is
       | helpful.
       | 
       | 2) Depending on what 3rd party services you use it may not even
       | be practical to have connectivity between auth and other
       | services, and if you do, the latency may be bad enough that you
       | wouldn't want it to be blocking every request. This is especially
       | compelling for hybrid environments, e.g. the 20 year old database
       | in a colo with your user data, and a new service being built for
       | you by consultants on a PaaS.
       | 
       | 3) People act like revocation is such a nightmare, but you only
       | need the auth service to sign invalidation tokens to be passed to
       | the client-facing services, and those services only need to
       | retain them for the max TTL of the auth tokens, after which they
       | can be evicted. Yes, that's something that could be motivated by
       | having a massive environment like Google, it could also just be a
       | way to keep costs down when you're paying by the byte of storage
       | or by the outbound request on some cloud. You could try to make
       | the argument that storing invalidation data is just as bad as
       | storing session data, but the key questions are "Where?" and "For
       | how long?", and then in some circumstances it breaks down very
       | quickly.
       | 
       | 4) You may not want sensitive user data stored in the
       | jurisdictions where you want to host your apps. That's not a big
       | company problem, it's dependent on the nature of the services you
       | provide.
        
       | greenthrow wrote:
       | This post is not very good. JWTs exist for good reasons. They may
       | not fit your needs, and if not, don't use them. But they exist to
       | allow Entity A to tell Entities B through Z that A had
       | authenticated the user and authorizes them without needing to
       | make API calls, and they serve that purpose well.
        
       | egberts1 wrote:
       | Wrote a brief recap of "permission" and "login" for
       | authentication from my work in JavaScript malwares.
       | 
       | It was a rush outline article with citations.
       | 
       | Large binning, salting of hash, and revocatable are my criteria.
       | 
       | Some toolkits that went out the window firstly are:
       | 
       | * auth0,
       | 
       | * Fusion auth, and
       | 
       | * Gluu.
       | 
       | So, some of the basic criteria are:
       | 
       | * User and password login instead of plain HTTP session cookies.
       | 
       | * HTTP-only over TLS v1.2+ (secured HTTP, HTTPS)
       | 
       | * ECDSA 1K or better
       | 
       | * SameSite [1]
       | 
       | * __Host prefix [1]
       | 
       | * preload HTTP Strict-Transport-Security header line [2]
       | 
       | * Bearer token supplied by API clients
       | 
       | * Don't listen on port 80... like ever. Or revoke token if over
       | non-port 443.
       | 
       | * DO NOT use JWT [3]
       | 
       | * DO NOT use CORS [4]
       | 
       | Hope the citations help more.
       | 
       | JWT, not recommended, IMHO.
       | 
       | https://egbert.net/blog/articles/authentication-for-api.html
        
       | flexterra wrote:
       | no
        
       | thayne wrote:
       | So first of all, JWT is part of the OpenID Connect specification.
       | So if you want to be either a service provider or identity
       | provider for OIDC, you need to use JWTs as an authentication
       | token in at least some cases.
       | 
       | Secondly, you don't have to hit the database on every request.
       | Unless you have really strict security requirements, you can have
       | a short expiration time on the jwt with a refresh mechanism, and
       | then you only have to check the database say once every 5
       | minutes.
       | 
       | Related to the above point, the database you check for the
       | "session" token isn't necessarily the same as the one used for
       | other data used in the request, even if you are much smaller than
       | Google or Facebook. It might not even ve the same type of
       | database.
       | 
       | Finally, even if it makes sense to use a "traditional" session
       | cookie for brower sessions, that probably doesn't make sense for
       | an external API, where the client may not have persistent cookies
       | at all, and there may not really be a concept of a session.
       | 
       | So as was mentioned in another comment, I think the answer to the
       | title question is a solid "it depends".
        
       | Savageman wrote:
       | Maybe it's irrelevant but for JWT to be passed as a Bearer in the
       | header Authentication header, it needs to be accessible from the
       | browser? Aren't httpOnly cookie safer in this regard? Or do we
       | see set the JWT in the cookie too?
        
       | osigurdson wrote:
       | What if you want to use AzureAD or Auth0? Aren't those services
       | completely built around jwts?
        
         | hnbad wrote:
         | AzureAD is built around OIDC. Yes, the tokens use JWT but that
         | can be treated as an implementation detail. The mechanism here
         | is OIDC, not specifically JWT. The tokens can be treated as
         | mostly opaque.
         | 
         | Also in that case _you_ aren 't using JWTs for authentication,
         | AzureAD is and you're integrating with it. And as I said,
         | you're integrating with it via OIDC.
        
       | drivebycomment wrote:
       | The main claim of the article is:
       | 
       | > jwt as authentication tokens are constructed for
       | Google/Facebook scale environments, and absolutely no one who is
       | not Google/Facebook needs to put up with the ensuing tradeoffs.
       | 
       | The first sentence is factually incorrect. Google doesn't use JWT
       | for most of its own authentication. Try analyzing their traffic -
       | web and mobile apps - and you'll find that none of their 1st
       | party applications / web use JWT. They do use JWT for OIDC, for
       | third parties, which makes sense since with OIDC/JWT, third party
       | sites can verify the token without talking to Google using a
       | standard. This is largely similar for Facebook.
       | 
       | JWT RFC starts with:
       | 
       | > JSON Web Token (JWT) is a compact, URL-safe means of
       | representing claims to be transferred between two parties.
       | 
       | Notice "between two parties". Of course, nothing stops from a
       | single party to use JWT, but claiming JWT was invented for
       | "Google/Facebook scale environments" implying they are using it
       | for their 1st party authentication is just factually wrong. JWT
       | was always meant to be an information transport between two
       | separate parties, like OIDC.
       | 
       | "Ensuing tradeoffs" here is essentially about stateless
       | authentication vs stateful authentication, and even there, this
       | "absolutely no one" is simply incorrect. There are many scenarios
       | where stateless authentication is sufficient, even for the
       | authentication for a single party (let alone between two separate
       | parties). Not all applications and use cases require the security
       | properties of stateful authentication - a sufficiently short
       | expiration would provide sufficient security in many cases,
       | making the loss of any security worth it for the added benefit of
       | simplicity and reliability with the stateless authentication.
       | 
       | Now with more nitpick:
       | 
       | The article claims, since "denylist" would require a database
       | read, it's equivalent to stateful authentication. Theoretically
       | that's true. In practice, denylist has some nice properties, that
       | makes it worthwhile if server-side logout is the only missing
       | feature you need from JWT. Denylist is often very small - if most
       | users of your application or service do not explicitly log out,
       | the number of denylist will remain very small. With the
       | expiration, the size can not grow indefinitely either. Thus, the
       | denylist you maintain can be much smaller than the record of all
       | stateful authentication - which makes it cheaper/easier to
       | replicate / cache across your systems than the full
       | authentication records. So "denylist" is definitely a legitimate
       | design option, with slightly different trade-offs than a full
       | stateful authentication.
       | 
       | ---
       | 
       | If I re-interpret the main claim of the article in the way I
       | think would make sense, it would be: services should prefer
       | stateful authentication, and the cost of stateful authentication
       | is lower than people imagine it to be. That I can be behind 100%.
       | As written, the article is at best some big exaggeration with
       | incorrect details and hidden assumptions.
        
       | manlobster wrote:
       | It's a lot easier to scale a revocation list than a list of valid
       | sessions, because the vast majority of incoming authentication
       | tokens are not revoked.
       | 
       | Tokens are extremely cacheable, so you shouldn't have to hit the
       | DB on every request in any case.
        
       ___________________________________________________________________
       (page generated 2024-05-27 23:00 UTC)