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