[HN Gopher] Should I use JWTs for authentication tokens?
___________________________________________________________________
Should I use JWTs for authentication tokens?
Author : pantalaimon
Score : 540 points
Date : 2024-05-27 15:31 UTC (1 days 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.
| finack wrote:
| Some computers make it harder than others.
| 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
| EthanHeilman wrote:
| Thanks for sharing this. I do a lot of work in this area
| and I had not come across PASETO before. It is an
| exciting project.
|
| The nonce is especially nice because it makes the token
| high entropy enough that if only the signature leaks an
| attacker can't brute force the full token. This isn't
| always true in OIDC JWTs.
| 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.
| koliber wrote:
| There are plenty of libraries. But supporting a
| production SAML service provider takes a lot of work.
|
| I've done this before. The first library I used had a
| horrible security issue that remained unfixed. We
| switched to one that seemed to be secure. Implementing
| SAML is non-trivial. Adding automated testing is also not
| something that required more senior people on our team.
| Getting engineers to understand how SAML work takes
| effort.
|
| Also, about one out of five SAML IdP's are unconventional
| in some way. They are a royal pain to support.
|
| The support burden of SAML is much higher than expected.
| Paying for Auth0 is cheaper than the engineering cost of
| supporting SAML, even with one of the existing libraries
| you refer to.
| 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.
| finack wrote:
| You don't need a cryptographer on payroll to install and
| configure an SSO library. Maybe your developers aren't
| skilled enough to do that, but it is not a challenge for a
| proper senior developer.
| 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.
| cryptonector wrote:
| Having to list the tokens to revoke is a problem in several
| ways. Obviously publishing the tokens themselves allows
| attackers to use them before relying parties get the revocation
| notice, so publish a token hash instead. But even publishing a
| token hash is annoying because you then have to record all the
| claims + token hashes issued, and that's a failure point.
| Instead you'd want to revoke _subjects_ (`sub`), but since
| tokens don't have to have those... (In enterprise systems
| though your tokens should name subjects.)
| 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).
| ec109685 wrote:
| User X's web browser calls Server A which makes a web
| service request to Server B that needs to authenticate
| that user X is making the call.
|
| What types of tokens do you suggest in each case?
| EthanHeilman wrote:
| To pitch my own project, OpenPubkey[0], it is designed
| for exactly this use case. OpenPubkey let's you add a
| public key to an ID Token (JWT) without needing any
| change at the IDP.
|
| 1. Alice generates an ephemeral key pair (if she is using
| a browser she can generate the key pair as a "non-
| extractable key"[1]).
|
| 2. Alice gets ID Token issued by Google that commits to
| their public key,
|
| 3. Alice signs her API request data to Service A and
| sends her ID Token to Service A.
|
| 4. Service A checks the ID Token (JWT) is issued by
| Google and that the identity (alice@gmail.com) is
| authorized to make this API call, then it extracts
| Alice's public key from the ID Token and verifies the
| signature on the data in the API call. Then it passes the
| signed data to Service B.
|
| 5. Service B verifies everything again including that the
| data is validly signed by Alice. Service B could then
| write this data and its cryptographic prominence into the
| database.
|
| Technically OpenPubkey uses a JWS, but it is a JWS
| composed of a JWT (ID Token) with additional signatures.
| OpenPubkey signed messages, like the ones passed via the
| API are also JWS.
|
| I'm working on a system where each service in the path
| adds their signatures to the signed message so you can
| cryptographically enforce that messages must pass through
| particular services and then check that at during the
| database write or read. Using signature aggregation, you
| don't get a linear increase in verification cost as the
| number of signatures increase. It doesn't seem to add
| much overhead to service meshes since they are already
| standing up and tearing down mTLS tunnels.
|
| The main question to me is how much autonomy do you want
| to give to your services. There are cases in which you
| want services to query each other without those services
| having to prove that the call originated from a specific
| authorized user.
|
| [0]: https://github.com/openpubkey/openpubkey
|
| [1]: https://developer.mozilla.org/en-
| US/docs/Web/API/CryptoKey/e...
| 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?
| unscaled wrote:
| DPoP described in RFC9449 - you can see from the RFC
| number it's quite new. I don't think there's wide support
| for it, but at least Okta supports it[1] and I think
| Auth0 are also working on adding DPoP.
|
| Is it good? I'm not a fan. To use DPoP safely (without
| replay attacks), you need to add server-side nonces
| ("nonce") and client-generated nonces ("jti", great and
| definitely not confusing terminology there).
|
| You need to make sure client-generated nonces are only
| used once, which requires setting up... wait for it... A
| database! And if you'll be using DPoP in a distributed
| manner, with access tokens then, well, a database shared
| across all services. And this is not an easy-to-scale
| read-oriented database like you'd have to use for
| stateful tokens. No, this is a database that requires an
| equal number of reads and writes (assuming you're not
| under a DDoS attack): for each DPoP validation, you'd
| need to read the nonce and then add it to the database.
| You'd also need to implement some sort of TTL mechanism
| to prevent the database from growing forever and
| implement strong rate limitation across all services to
| prevent very easy DDoS.
|
| It seems like the main driving motivation behind DPoP is
| to mitigate the cost of refresh tokens being exfiltrated
| from public clients using XSS attacks, but I believe it
| is too cumbersome to be used _securely_ as a general
| mechanism for safe token delegation that prevents "pass-
| the-token" attacks.
|
| [1] https://developer.okta.com/docs/guides/dpop/nonoktare
| sources...
| jmdc wrote:
| I agree that DPoP - especially the nonce - is quite
| complex, but I don't think it's as bad as you make out.
|
| Proof tokens can only be used for a narrow window of time
| (seconds to minutes), so you just need a cache of
| recently seen token identifiers (jtis) to do replay
| detection. And proof tokens are bound to an endpoint with
| the htm and htu claims. They can't be used across
| services, so I don't see a need for that replay cache to
| be shared across all services.
| jmdc wrote:
| DPoP is an OAuth extension that defends against token
| replay by sender constraining tokens. It is a new-ish
| spec, but support is pretty widespread already. It's used
| in a lot of European banking that has pretty strict
| security requirements, and it's supported by some of the
| big cloud identity providers as well as the OAuth
| framework I work on, IdentityServer. We have sample code
| and docs etc on our blog:
| https://blog.duendesoftware.com/posts/20230504_dpop/
| rwdf wrote:
| It's a new proposed standard. Where I work (in healthcare
| in Europe) we have it as a requirement for any new APIs
| we offer public access to. We have our own auth service,
| but looks like Okta already offers DPoP.
| 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.
| Aeolun wrote:
| Don't see how those prevent tokens from being misused?
| They just prevent anyone from issuing tokens as you. Not
| by themselves, but if you implement your server
| correctly.
| chipdart wrote:
| > Don't see how those prevent tokens from being misused?
|
| The purpose of a nonce is to explicitly prevent the token
| from being reused.
|
| The purpose of the other claims is to prevent them from
| being accepted (and used) in calls to other services.
|
| If you implement your server correctly, each instance of
| each service is a principal which goes through auth flows
| independently and uses its own tokens.
|
| There is no token sharing.
| ramchip wrote:
| > (or worse: using a shared-secret for signing tokens
| instead of asymmetric cryptography, ugh)
|
| What's so terrible about that? Several security engineers I
| trust favor designs with symmetric crypto, e.g. Fly.io
| https://fly.io/blog/macaroons-escalated-quickly/ and
| Facebook https://eprint.iacr.org/2018/413.pdf
| ak217 wrote:
| It limits your ability to compartmentalize your
| infrastructure, establish security perimeters, and
| provide defense-in-depth against vulnerabilities in your
| dependencies.
| locallost wrote:
| Large companies have fallen into this trap [1]. So you are
| right that aud addresses the problem, but it's widespread
| enough to question if it really affects just coding camp
| content farms. Hard to grok is probably possibly in some
| way a design flaw.
|
| [1] https://salt.security/blog/oh-auth-abusing-oauth-to-
| take-ove...
| 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."
| dagss wrote:
| Are you sure? I have never interpreted it this way and it
| is the first way I hear this interpretation.
|
| My understanding: To use something "for real" on an actual
| project, not just toy around with it. (What you use can be
| good or bad, expression doesn't say)
| Zecc wrote:
| My interpretation has always been the same as mceachen's,
| but other comments in this sub-thread have thought me I
| am wrong and your understanding is correct. Today I
| learned.
|
| For what it's worth[0]:
|
| > If you do something in anger, you do it in a real or
| important situation as it is intended to be done, rather
| than just learning or hearing about it
|
| [0]
| https://dictionary.cambridge.org/dictionary/english/in-
| anger
| 7sidedmarble wrote:
| No, it's a military term. Firing a cannon in anger for
| instance means firing at the enemy, rather than in
| training.
| 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.
| dilyevsky wrote:
| Yes it's an old britishism - comes from "shots fired in
| anger" (as opposed to training)
| 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.
| davedx wrote:
| Depends on your business. Most b2b companies probably don't
| need to care about invalidation, at least not in the startup
| phase. For B2C it's going to be more important. But ask
| yourself "why do I need to pre-emptively invalidate tokens?"
| thayne wrote:
| Same applies to non-micro service architectures.
| ak217 wrote:
| > doesn't seem to address microservice architectures at all
|
| Or just, you know, service architectures. Most microservice
| architectures I've seen go way too far down the route of
| breaking up services and their infrastructure to an impractical
| level. But all you need in order to make JWTs really useful is
| two federated services. This happens all the time, often in the
| course of some partnership, acquisition, or just an
| organizational structure meant to decouple 2+ teams from each
| other.
|
| Based on their mention of a single framework connecting to a
| single database, OP seems to have never moved past the point of
| developing a single service. Which is fine! It makes things
| simpler for sure, and you can get very far with that. But they
| are then dispensing advice about things they don't seem to know
| much about.
| 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
| Aeolun wrote:
| Aren't JWT bearer tokens certificates already? Only the issuing
| server has the private keys, and the public keys are used to
| validate that server signed them?
| magicalhippo wrote:
| This is the other way around. It allows the user (token
| holder) to sign messages "using" the ID token.
|
| To be able to sign a message you not only need the ID token
| but also the private/signing key, and the corresponding
| public key is bound to the ID token (using the nonce field).
|
| Thus you can prove that not only did Google say you are you,
| but you possess the signing key associated with the ID token
| that says so. Thus I can be sure someone else didn't just
| steal your token in flight or from a log file for example.
| EthanHeilman wrote:
| Certificates use a signature to bind an identity to a public
| key.
|
| JWT bearer tokens use a signature to issue an identity, but
| that don't include the public key of that identity. The
| issuer has a public key, but the issuee does not.
|
| There are plenty of JWTs that are certificates:
|
| * proof-of-possession JWTs,
|
| * self-issued JWTs, etc...
| magicalhippo wrote:
| > OpenPubkey let's you turn JWTs bearer tokens into
| certificates.
|
| This looks really awesome, thanks for sharing.
| 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.
| moduspol wrote:
| The issue from parent comment is that it needs to be on every
| _access_ request, not every _login_ request.
| 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
| finack wrote:
| What? Session tokens have been around for like 30 years now,
| and every web framework worth using has a rock-solid
| implementation; you haven't had to do it yourself since Full
| House was putting out new episodes.
| rendall wrote:
| Binding a session to client details like IP addresses and
| user agents requires enough fiddling that it's no longer the
| no brainer to use session tokens over JWTs that the article
| makes out, is my point.
| angoragoats wrote:
| By "binding a session to client details like IP addresses
| and user agents" do you mean restricting the session so
| that only the original IP/UA can make use of the session
| token?
|
| If so, most robust session-based authentication libraries
| can already store this data for you (e.g. Devise's
| `trackable` module). Actually locking down the session so
| it can't be used by different IPs/UAs would require custom
| code on the server, whether you're using JWTs or session
| tokens.
|
| So JWTs provide zero advantage here, unless I'm
| misunderstanding something.
| 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.
| pests wrote:
| > the only way to get it afaik is to hijack the client
| device or somehow hijack the server.
|
| Yet we have millions of passwords in dumps across the
| internet. Maybe hijacking the client or server is more
| common than thought?
| moomoo11 wrote:
| I think you're conflating a few things.
|
| Passwords being leaked is due to noobs and idiots in
| charge of systems, and probably not using an actual auth
| provider.
|
| It really isn't that hard.
|
| 1. Send secure information over SSL. If some noob-tier
| dev decides that's too advanced for them, congrats I
| guess for being stupid.
|
| 2. Store passwords with hashing and salting. If you use
| an auth provider, like auth0 or firebase even, they will
| do this for you because they're not noobs. A noob-tier
| dev who stores plaintext passwords in a database with
| insecure connection and postgres:postgres is again stupid
| af.
|
| Most of those leaked passwords are because of this. And
| don't think some Fortune 500 is not stupid. They
| outsource their development to Accenture or Detoilette,
| or any of the other outsourcers where they pay some
| "Software Architect" $8/hr to secure banking information
| (while charging the client $150/hr). I'm not throwing
| shade, but these companies are cheap af and throw bodies
| at the problem instead of experience and brains. I have
| direct experience with this, so I know how bad it is.
|
| Don't confuse people being stupid (very common, 90% of
| any population) with a failure in a technology that
| others who don't understand it claim makes it inferior or
| something.
|
| The internet and all the technology you use today is
| glued together by the <10% of people who actually
| understand computers, networking, and problem solving.
|
| Just because a noob-dev uses session tokens doesn't mean
| it will be any secure if they fail those 2 points I
| mentioned. Those are so deadass simple to mitigate,
| anyone who purposefully skips on them should be named and
| shamed, and receive a 10 year cooldown from being a
| software developer.
| 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?
| mrkeen wrote:
| > If a short session time isnt good enough, you can use a
| simple key store to check for revoked tokens.
|
| It's not bad solution per se, but it does negate JWT's
| main value proposition, which is to not need such a
| store.
| 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.
| pan69 wrote:
| But if the jwt was leaked before the client forgot it,
| the jwt itself is still valid and can continued to be
| used by an attacker.
| stkdump wrote:
| I wonder if an extension to the concept of jwt that
| extends the cryptographics chain down into some hardware
| component such as a TPM or secure enclave is the right
| answer. Basically the payload of the token could contain
| a pubkey for checking a signature on the request payload.
| The logout button would then have two local effects on
| the client side: delete the token and tell the hardware
| component to forget the private key.
| xorcist wrote:
| Well, hence (functional). Making the client forget a
| token sounds trivial. But there's a long tail of clients
| out there, and many cases where things might get more
| complicated.
|
| Maybe I'm damaged from working in a regulated industry,
| but a (possibly malicious) client who went through the
| logout process and could prove someone else reused the
| token after logout might have a case. Or another of a
| myriad of unknown possibilities.
|
| It's all very unnecessary. There's a reason we all used
| to invalidate trust server side. It's just so much easier
| to reason about.
| 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.
| stavros wrote:
| Because logging out is also supposed to invalidate the
| token so it can't be reused by anyone who may have stolen
| it.
|
| This thread is really making me despair. If you don't see
| a problem with JWTs, you aren't experienced enough to use
| JWTs.
| sweetjuly wrote:
| I think you need to take this a step further and really
| define your threat model instead of being despaired :)
|
| If an attacker is able to steal a victim's cookie
| database, their system (or at the very least, their
| browser) is already deeply compromised. It is very likely
| that an attacker with such capabilities could prevent
| your website from ever sending the logout request
| (install a browser extension which blocks it, inject into
| the render process to silently drop it, modify the cached
| JavaScript on disk to inject code into the site, etc.).
| The logout functionality only works insofar as you trust
| the client, and in any circumstances where the client's
| cookies could be stolen you really can't trust the
| client. So logout revocation is not really a meaningful
| security boundary.
| johtso wrote:
| How about the scenario of a stolen device that's logged
| into the service. The victim logs in on another computer
| to try and reset their password and lock the thief out of
| the compromised account.
|
| This can't be done without revocation.
| sweetjuly wrote:
| This is a different feature than a simple logout button
| though (something along the lines of "sign me out
| everywhere"), and many (smaller) websites don't actually
| support this. As far as I can tell, the very website
| we're on doesn't support it :) The parallel use case is
| SSO invalidation where you may need to immediately revoke
| access to a service after an employee is terminated.
|
| You would need revocation in this case. Implementing this
| is easier when you already have database backed tokens,
| but unless you intend to support these features JWT is a
| totally reasonable engineering decision.
| thomasfromcdnjs wrote:
| I feel ya.
|
| You have to store invalidated tokens anywhere they might
| pass through a service, which means you have to persist
| them for as long you can predict that there expiry will
| last. Simply putting them in a memory database isn't 100%
| if that db gets flushed, and then you might start storing
| them in a disk database, which at that point, you might
| as well have just read the db in the first place using
| cookie auth.
|
| In microservices, you generally have to put an
| invalidated JWT cache between every service, or
| compromised JWT's are just floating around your intranet.
|
| I've worked at a plethora of places who have JWT's who
| have no invalidation strategy what so ever, the majority
| of developers think that when you log out and the user
| has forgotten the JWT then you are all good......
| mgraczyk wrote:
| You can do what Google and everyone else does, which is
| store the revoked tokens. At scale this is easy to do
| efficiently and rarely requires a network request since
| the number of revoked unexpired tokens is small.
| andoando wrote:
| How does infrequentcy of revoked tokens reduce requests?
| Dont you have to check every token to see if its revoked?
|
| Or Do all the server instances store a copy of all
| revoked tokens in memory/local db?
| mgraczyk wrote:
| All the servers can store a copy or a bloom filter
| because the number of revoked tokens is small and doesn't
| change often
| 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.
| zdragnar wrote:
| The advantage of redis or similar kv DBs / caches comes
| in being lighter and faster than a full second database,
| mostly.
|
| The secondary advantage is you don't need to deal with
| cookie storage, sticky sessions or anything else along
| those lines.
|
| If you're manually hand crafting a server, go for it. If
| you're treating them like cattle not pets, going
| stateless with a bearer token tends to be easier.
| 4star3star wrote:
| How do you find out a single token got leaked within the
| token lifetime? If it's that easy to detect a leaked token,
| why aren't you stopping the leak in the first place?
| 015a wrote:
| Then you can hit the db.
|
| I don't understand this argument against JWTs; if
| instantaneous session revocation is important for your use-
| case, versus JWTs more typical 5 minute or 60 minute
| expiration, there is nothing about JWTs which makes them
| poor candidates for going to the database as you would a
| session token. And, you get all the other benefits.
|
| One example where this can matter: I've seen JWTs used in
| defense-in-depth scenarios where you've got an API gateway
| that does the initial JWT validation, including a round-
| trip to the database to check for revocation, but then had
| microservices behind the gateway only check the signature.
| Traditional session keys would require a database roundtrip
| for every validation, which could number in the dozens for
| a single API request.
| treve wrote:
| OAuth2 has no dependency on JWT, and _most_ authentication
| cases don't need OIDC, OAuth2 is enough.
| tracker1 wrote:
| I'd add that it's easier to abstract your software service from
| authentication. It's allowed me to write bridge signing from
| AzureAD, Okta etc, to a supported application deployed to
| differing environments on client hardware and readily
| integrating to different SSO systems.
| 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.
| finack wrote:
| Amazing how using a session ID stored in a cookie was
| entirely possible in 2005, but is somehow out of our reach
| with today's hardware.
| kbolino wrote:
| A simple session cookie does not protect against CSRF. In
| 2005, session IDs were generated with low quality RNGs
| and too few bits making them easy to guess. OWASP
| happened for a reason.
| rblatz wrote:
| It's not hard to stand up, managing state across sessions
| and versions of your app is hard. For example a site I
| use frequently the Morgan Stanley portal is stateful and
| you can only be logged in from a single device/tab at
| once.
|
| Most websites don't need it, and it makes things harder
| to manage when rolling out new versions of your services.
| Life got significantly easier once I moved away from
| stateful services.
| rblatz wrote:
| Yeah, and life was tough back then. My services have gotten
| significantly easier to manage since moving away from
| stateful services.
|
| Even at a new company I don't think I'd ever want to go back
| to stateful sessions. I'm not close to Google or Amazon
| scale, and managing state was significantly harder than
| dealing with JWTs.
| 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.
| Aeolun wrote:
| 95% of the non-wordpress part of the web.
|
| We're rebuilding our microservice hell as a monolith
| anyway.
| 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.
| Aeolun wrote:
| I'm not sure what you are trying to say here? That dealing
| with refresh token expiry revocation for a single system (and
| two sessions) is better than dealing with expiry and
| revocation for 3?
|
| I see some strong arguments for standardizing on a single
| one.
| 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
| finack wrote:
| No, it's a necessary feature if your credentials get
| stolen, which wouldn't surprise me considering how many
| people just cram JWTs into local storage, which is not the
| same as a secure cookie and has weaker security. Either
| you're setting the expiry time real low (which still won't
| stop someone who has four minutes 59 seconds left to wreck
| your stuff, because computers are fast), or you're
| maintaining a blacklist, which means, congratulations,
| you've just reinvented overly-complicated session tokens.
| redman25 wrote:
| You could probably rotate the secret which would invalidate
| all existing sessions.
| 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.
| ak217 wrote:
| Not really. A pub/sub bus cluster (or PaaS) is pretty
| different from a database.
| akerl_ wrote:
| I'm not talking about the pub sub cluster.
|
| If you have a pub sub cluster that you push revocation
| details into, and running servers subscribe to that feed
| and then track a rolling list of tokens that would
| otherwise still be active but have been revoked, you are
| effectively storing a revocation database on every edge
| node.
| ak217 wrote:
| Again not really. If the pub/sub broker is persistent,
| you don't have to persist the revocation list on edge
| nodes. And just pointing out that it's a db in some loose
| sense of the word doesn't help with the actual challenge
| of organizing the flow of data reliably in a federated
| system (i.e. one that can't share a single database).
| 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.
| meling wrote:
| Here it is https://uis.brage.unit.no/uis-
| xmlui/bitstream/handle/11250/3...
| hu3 wrote:
| Thank you! I'm looking to write a paper about a software
| I'm developing and this will help immensely since it's a
| fitting format.
| 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.
| wokwokwok wrote:
| I mean, to be fair, the article literally calls out a fairly
| reasonable checklist.
|
| Do you maintain a database of JWT session tokens for refresh
| and revoke?
|
| Do you have a real session that you load for every user every
| request _anyway_?
|
| If the answer is 'yes', then the answer to 'use JWT' isn't
| 'it depends'.
|
| It's no.
| _heimdall wrote:
| The author here seems to be arguing that you should
| effectively never use JWTs. That, in my opinion, is a
| mistake.
|
| JWTs have absolutely been over-hyped for the last 8-10
| years, but they do have a use and you don't have to be at
| the scale of Google for it to be the right approach.
|
| Software isn't as simple as creating a checklist of a few
| basic categories and saying there is always a right or
| wrong answer. The answer should be "it depends" because
| there are many more factors at play when deciding something
| as fundamental as authentication and authorization.
| meindnoch wrote:
| Ok, then show us an example scenario where using JWTs
| makes sense, while the author's checklist says it
| doesn't.
| _heimdall wrote:
| I may not have been clear there. I'm not saying the
| author's list is wrong, I'm saying its incomplete.
|
| For starters, the blog post leads with the premise that
| the answer is always "No". Even ignoring that as playful
| banter, the checklist is way to broad to be universally
| true.
|
| > 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.
|
| > 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.
|
| > You need additional relationships between the user
| object and other objects in the database. You hit the
| database on each request.
|
| > Your service does anything at all with data in the
| database. You hit the database on each request.
|
| These all assume that I authorization data _and_ that the
| user data lives in the same database. I may store my own
| user object with a unique ID that references an
| authenticated user, while the author flow is actually
| managed by an entirely different service (whether first
| party or third party). I also may have my user data
| stored in a separate database, say for legacy reasons or
| data security /integrity requirements. Not every database
| is crested equal, its totally possible that one database
| is a better fit for user data while a totally different
| database is needed for application data.
|
| Coming up with a list of broad scenarios and claiming
| that if you check any one there is _never_ a reason to
| pick JWTs over sessions is misguided and overly
| simplistic. Context _always_ matters.
|
| edit: formatting
| meindnoch wrote:
| >These all assume that I authorization data and that the
| user data lives in the same database
|
| Please tell us how the following assumes that
| authorization data and user data lives in the same
| database:
|
| "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."
| _heimdall wrote:
| It doesn't have to assume that, again because _context
| matters_.
|
| If authorization data is stored outside my database, I
| may not store _anything_ related to that user other than
| their unique ID. I may not know anything about the JWTs
| because a middleware talking to the external
| authorization service authorizes a request before I ever
| query my database.
|
| I could also store valid JWTs in my own database or in a
| caching layer, say with redis for quick access. There's
| nothing wrong with that, but without more details on
| _what_ someone is building and what it needs to be
| designed for there is no absolute right or wrong answer.
| meindnoch wrote:
| I don't see how anything you said would refute OPs
| premise, that if you want proper logout [1] in your app,
| you can't use JWTs without constantly querying whether a
| particular JWT should be accepted or not, from which it
| follows that this query mechanism may as well be a
| traditional database with a "sessions" table.
|
| How you organize your data, your services, your
| middleware, etc. does not change this the slightest,
| hence are irrelevant.
|
| ----
|
| [1] proper logout is instant (this invalidates the "just
| use a JWT with short timeout!" argument), and prevents
| session stealing (this invalidates the "just throw away
| your JWT to logout" argument)
| 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.
| a_random_canuck wrote:
| In my experience for medium sized services it's still
| better to have everything talk to the same authentication
| database.
|
| Postgres has insanely good read performance. Most
| companies and services are never going to reach the scale
| where any of this matters, and developer time is usually
| the more precious resource.
|
| My advice is always, don't get your dev team bogged down
| supporting all this complicated JWT stuff (token
| revocation, blacklisting, refresh, etc) when you are not
| Facebook scale / don't have concrete data showing your
| service really truly needs it.
| j16sdiz wrote:
| +1
|
| For mostly-read flow like authentication, a centralized
| database can scale really well. You don't even need
| postgres for that.
|
| If you have mutable state, JWT can't help you anyway.
|
| JWT start make sense only when you are doing other
| hyperscaler stuffs and you can reuse part of those
| architecture
| PaulHoule wrote:
| Funny, people used systems like JWT in the late 1990s.
| Back then you couldn't really trust the session mechanism
| in your language because inevitably these had bugs and
| would toss your cookies for "no reason at all".
|
| I was inspired by https://philip.greenspun.com/panda/
| circa 2001 to develop a complete user management
| framework based on that kind of cookie which had the
| advantage over other systems that the "authentication
| module" it took to get authentication working in a new
| language was maybe 40-100 lines of code. Software like
| PHPNuke that combined second or third rate
| implementations of apps all in the same codebase was the
| dominant paradigm then, the idea that you could pick
| "best of breed" applications no matter what language you
| were using was radical and different.
|
| I used the framework for 10+ projects, some of which got
| 350,000+ active users. As an open source project it was a
| complete wash. Nobody got interested in user management
| frameworks (as opposed to writing your own buggy,
| insecure and hard-to-use auth system in a hurry) until
| around 2011 or so when frameworks based on external
| services all of a sudden popped up like mushrooms. Seemed
| like the feature I was missing was "needs to depend on an
| external service that will get shut down with the vendor
| gets acquired"
| stickfigure wrote:
| Alternatively, just don't worry about token revocation
| and all that complicated stuff? So you have a window of 5
| minutes (or whatever your access token expiry is) that
| you can't revoke - is that a big deal?
|
| A simple JWT implementation isn't that complicated, but
| you have to accept some limitations.
| andrewmcwatters wrote:
| > It's an anti pattern to have every service talk to the
| same database just to authenticate every request.
|
| Bullshit.
| mynameisvlad wrote:
| Do you want to expand on that? Because having a single
| point of failure certainly seems like a horrible practice
| when that single point goes down.
| andrewmcwatters wrote:
| You're already talking to stateful systems to do anything
| meaningful. A in-memory cache on top of session retrieval
| is so trivial and adds so few microseconds that it's
| imperceptible even at large volumes of traffic.
|
| If you're having trouble with that, you've got bigger
| issues. Any regular work queries will take longer, and so
| it's not even a meaningful area of concern if you broke
| down a request from end to end on a flame graph.
| mynameisvlad wrote:
| > You're already talking to stateful systems to do
| anything meaningful.
|
| Yeah, so? They don't have to be talking to the _same_
| system, and in fact it was _literally_ what you called
| bullshit to originally.
|
| > If you're having trouble with that, you've got bigger
| issues.
|
| That does absolutely nothing to changing the fact that a
| SPoF is _still_ an anti-pattern that should be avoided.
|
| For that matter...
|
| > A in-memory cache on top of session retrieval is so
| trivial and adds so few microseconds that it's
| imperceptible even at large volumes of traffic.
|
| Also does absolutely nothing to change that fact. You
| have done nothing to _actually_ elaborate on why it's
| totally not a horrendous idea to have everything
| communicate to the same database. Just because there's a
| caching layer does not mean that fresh data wouldn't be
| available if a SPoF goes down, which, once again, is the
| whole point here.
| 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.
| rezonant wrote:
| I'm not sure cache was the right word in the parent
| post-- you don't want to use a cache (at least one with
| LRU/bounded size) to store revocation without a backing
| store, or else the revocation could get pushed out of the
| cache and become ineffective. The backing store (likely a
| DB) would require such cleanups once the revocation
| record is no longer relevant.
| sturgill wrote:
| Potentially you take both at once: use something like
| DynamoDB as the storage layer that also supports TTL
| natively.
| jupp0r wrote:
| I would challenge your assumption. Unless you absolutely
| need to have 100% durable, consistent revocations for
| some reasons, something like memcached is perfect here as
| the worst case scenario in case of a failure is a slight,
| temporary degradation in security without any visible
| user impact or operations nightmare (ie restoring
| backups). This assumes that your token lifetime is
| reasonably short (at least for access tokens), refresh
| tokens are a different story but only need to be tracked
| at the authn service, not globally.
| rezonant wrote:
| If the revocation use case is soft, then totally fair.
| But if the application is potentially dangerous and the
| user says "Sign out all devices", I think that should be
| a deterministically successful operation. Similarly, if
| there is a compromised account in an organization, I'd
| like to be confident that revoking all credentials was
| successful.
|
| Revocation of tokens can be done for a simple logout
| operation, in which case the stakes are low, but more
| often it is the "pull the fire alarm and get that user
| out", and in that case it should be reliable.
| 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.
| makeitdouble wrote:
| As you point out, in most use cases a random token will be
| fine and it all comes down to how and where it is stored.
|
| But that also means that you can have JWTs that are used as
| "random token" for most of your app, cost to produce them
| isn't high, and only make use of the additional capacities
| for instance when
|
| - when you want to check signatures (e.g. reject before
| hitting your application layer)
|
| - store non sensitive base64 data that you want before
| restoring the session
|
| Creating and handling JWT is only as costly and complicated
| as you want it to be, so there's IMHO enough flexibility to
| have light use with very few penalities for it.
| bcrosby95 wrote:
| Why not just stick your auth token in the cache. It's
| supposed to expire anyways.
|
| Back in the day we used memcached for our primary store for
| all sorts of ephemeral things. Including user sessions.
| withinboredom wrote:
| Items are evicted from caches all the time for non-
| expired reasons. Memcached, in particular has "slabs"
| (spaces for objects of a certain size) and once those
| slabs are full, items are evicted to make space for new
| items.
| torginus wrote:
| Honestly, do you even need support for revoke? If you have
| a token whose lifetime can be measured in 2-3 minutes, I
| don't think the abuse potential is huge, especially when
| some other security measures are in place.
|
| Thing is, token refresh service can be stateless, but
| adding a revoke service basically kills JWTs main
| advantage, since every time we check its validity, we need
| a query to see if its been revoked.
| nine_k wrote:
| Revocation is needed because you want to disable access
| to an intruder in the very second you detect unauthorized
| access using a stolen token. Same for certain kinds of
| banned users who must lose access immediately.
|
| But since such a revocation list is going to be short
| (usually 0 entries, dozens at worst), it's trivial to
| replicate across all the auth service nodes (which can as
| well be worker nodes) or keep it in Redis replicated per
| DC, with sub-millisecond lookup times.
|
| Things get harder if you want a feature like logging out
| other sessions, or just an explicit logout on a shared
| computer (think about business settings: stores,
| pharmacies, post offices), you may have to have larger
| revocation lists. This may still not be a problem: a
| million tokens is a few dozen megabytes, again, a per-DC
| replicated Redis cluster would handle it trivially and
| very cheaply.
| torginus wrote:
| I still feel like the need for revocation kills the
| simplicity of JWT and thus the reason for its existence.
|
| I'm of a more gradual opinion regarding this - say you
| operate a movie streaming service and control access to
| movies via JWT. It's not a problem if an attacker has
| access for two more minutes than intended.
|
| If you are talking to a single client, I think checking
| the remote IP address and encoding it in the token might
| work to see if the token is not stolen, but don't quote
| me on that.
| g15jv2dp wrote:
| It's a complicated problem. I don't see why it should
| have a simple solution.
| stickfigure wrote:
| > Revocation is needed because you want to disable access
| to an intruder in the very second you detect
|
| I get that this has conceptual appeal, but I doubt this
| makes any difference in real life. Unless you have some
| very sophisticated infrastructure, it takes many minutes
| to discover the issue and then many more minutes even to
| decide what to do about it. A few extra minutes to cut
| off access is probably not going to make a big difference
| one way or another.
| nine_k wrote:
| An intruder might be not a sophisticated black hat
| hacker. It could be somebody who picked up an unlocked
| phone or keyboard.
|
| When I had a chance to design a token-based authn/authz
| system, we had two types of tokens, general access (with
| hours of expiration, mostly read-only access) and
| privileged access, with expiration time set to a minute
| or so. All auto-refreshed on use, all separately
| revokable.
| withinboredom wrote:
| All you really need for revocation in a revocation
| service are two fields: user id + inb (issued not before)
| and a bloom filter.
|
| To revoke a token:
|
| 1. issue a new token to the revoker that is issued at
| current time (if business rules require revoker to be
| logged in).
|
| 2. set user inb to current time - 1 second with a TTL of
| longest issue * 1.5.
|
| 3. Add user to bloom filter.
|
| 4. upload bloom filter to s3, every service downloads
| this every 5 minutes.
|
| 5. Then on request, check bloom filter. If the user id is
| in the bloom filter, check with revocation service that
| inb > issued time.
|
| This is probably less than five hundred lines of code and
| pretty easy to maintain.
| littlecranky67 wrote:
| Often overlooked middle-ground that vastly simplifies
| your revocation logic: Just have a single field "not-
| issued-before" timestamp assigned to each user account.
| Instead of revoking a single token, you have a "log out
| from all devices" logic - i.e. you revoke all tokens at
| once based on their "iat" claim (issued at). No need for
| revocation lists alltogether, you just make sure any
| tokens "iat" is never before the "not-issued-before"
| associated with the user. Sure, this is not as perfect UX
| as being able to revoke individual tokens, but token
| revocation in generall is something only a fraction of
| your uses is ever going to need.
| withinboredom wrote:
| Yeah, this works very well. A nice "log me out of
| everywhere, including this device" link is often all you
| need on the settings page.
|
| It also makes e2e testing very easy since you should be
| logged out after pushing that button.
| pico303 wrote:
| How about invalidate the user's refresh token and the
| public signing key, which forces everyone to refresh and
| then logs out the hacked account. If it's really serious,
| lock the account before doing this so the user can't
| login again.
|
| But yeah, if you have a revoke service, might as well
| just use session keys.
|
| Edit: typo
| littlecranky67 wrote:
| No you don't, thats why i.e. even big players like Amazon
| with their AWS Cognito service (OAuth/OpenID Connect)
| don't even support revoking access tokens (only refresh
| tokens).
| devjab wrote:
| You don't need jwts to pass internal permissions. We don't,
| but we still extract claims from a jwt token at the
| beginning of a user flow. Then later we only use the claims
| to determine which resource a user has access to.
|
| It's not necessarily easier than just passing the jwt, but
| with our internal setups where when you first pass through
| the authorisation system, our traffic on your behalf is
| secure it doesn't really warrant a reason to decode your
| token multiple times rather than simply passing your access
| permission claims.
|
| We do still pass your jwt between isolated "products" where
| your access request doesn't pass through dapr, but rather
| back through our central access gateway and then into the
| other "product". A product is basically a collection of
| related services which are restricted to be a business
| component. Like a range of services which handles our solar
| plants, and another business component which handles our
| investment portfolios, and so on.
| DeathArrow wrote:
| >If we're talking about a web session, time-limited
| randomly-generated session tokens that are stored in a DB
| still work fine.
|
| How is this better than JWT if we have 30 microservices
| called from front-end?
| nicoburns wrote:
| > don't cache your user/auth database, but have a
| distributed cache of JWTs that have been revoked
|
| My understanding was that this is the ENTIRE benefit of
| JWTs (over plain session token): they allow you go from a
| allowlist to a blocklist, which is more efficient at really
| large scales because you only have to store expired
| sessions (until their time-limit expires) rather than every
| session).
|
| And if you're not doing this then there's no point in using
| JWTs (which will be the case for most people).
|
| Are there any other benefits I'm missing?
| andrewmcwatters wrote:
| > you only have to store expired sessions (until their
| time-limit expires) rather than every session).
|
| I don't know of any companies that even do this. As far
| as I know, most use cases store nothing, except for of
| course the client storing the response.
| turtlebits wrote:
| It's not a trend. Those on the extreme ends of the spectrum
| are always the most vocal.
| DeathArrow wrote:
| >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.
|
| 100% this. I am tired of you don't need microservices, you
| don't need JWT, you don't need Kubernetes, you don't need
| ElasticSearch, you don't need IAM, you don't need Redis, you
| don't need Mongo and everything should stay in one SQL
| database.
|
| Things are being used not because they exist, because people
| want to be fancy or because they don't have something better
| to do. Things are being used because they solve problems and
| do so with least effort possible.
| qaq wrote:
| "Things are being used because they solve problems and do
| so with least effort possible" in an ideal world sure in
| the real world there are many factors that influence
| technical decisions often having nothing to do with actual
| problem being solved
| zimpenfish wrote:
| Having worked at many places over the last 30 years, yes,
| there is definitely "resume-driven development" where
| people pick something they want to put on their resume to
| solve a problem regardless of its suitability to the task
| in hand.
|
| There's also "blinker-driven development" where people
| pick the solution based on their own personal set of
| hammers rather than, again, something more suitable.
|
| (There's loads of these though - e.g. "optimisation-
| driven development" where the solution MUST GO BRRRRR
| even if the problem could be fixed by Frank typing in
| "Yes" once a week. "GOF-driven development" where
| everything has to rigidly fit into a GOF pattern
| regardless of whether it actually does. "Go-driven
| development" where everything has to be a interface and
| you end up reading a method called Validate which calls
| an interface method Validate which calls an interface
| method Validate which calls an interface method Validate
| and you wake up screaming every morning because why just
| wtf why please help me pleasehelp)
| sunshinerag wrote:
| chuckle ... how far did you go into the validate rabbit
| hole
| zimpenfish wrote:
| Thankfully it was only 3 interfaces down.
|
| The whole codebase is riddled with the same kind of
| layering but we do now have guidance about doing stuff
| like that ("DON'T") and a plan to simplify some of the
| worst offenders (like the multi-layer `Validate` hell
| hole.)
| DeathArrow wrote:
| If I'd find myself in a place where they do "GOF-driven
| development" or "Go-driven development" I'd search for
| another job ASAP.
|
| I don't say what you describe doesn't happen, but it's my
| impression that most people try to adopt solutions that
| minimize costs and development time (which also
| translates to money). 99% of the time it's not "do the
| best thing to satisfy solve this problem" but it's "solve
| this problem as fast as possible, without adding
| additional costs and using as few developers as
| possible".
| zimpenfish wrote:
| > "solve this problem as fast as possible, without adding
| additional costs and using as few developers as possible"
|
| Agree with that but from my experience that's more like
| 20% of the time. The rest is the various kinds of
| bullshit development where people are padding resumes,
| having boss's pet hobby horse forced on them, latest
| shiny flimflam, etc.
|
| (A decent chunk of that 30 years has been contracting and
| that tends to be at places with problems which might be
| biasing my sample set.)
| qaq wrote:
| Well in big orgs people get shuffled around teams so even
| if you joined a team that is aligned with the way you
| feel things should be done you might end up in totally
| different env. after a period of time.
| ggregoire wrote:
| > there is definitely "resume-driven development" where
| people pick something they want to put on their resume to
| solve a problem regardless of its suitability to the task
| in hand.
|
| Or people in this industry are geeks and curious and like
| to try new stuff and technologies just for fun?
|
| That's the case for the majority of people I've worked
| with.
| zimpenfish wrote:
| > like to try new stuff and technologies just for fun?
|
| Sure but do that at home or on POCs. Not on production
| code.
| rbanffy wrote:
| > everything should stay in one SQL database.
|
| At least on different schemas.
|
| That and don't let one concern access data from another, or
| you'll have to coordinate schema changes between those
| different concerns.
| kayo_20211030 wrote:
| JWT's really can span this middle ground. They're helpful in
| answering the who-are-you question without resorting to
| elaborate db work. Even middle-ground monoliths are often
| deployed across more than one independently operating web
| server (say, JVM processes) and JWT's ensure that each server
| answers the who-are-you question with the same answer - the
| code is the same, and although the process space is different
| on each web server, the answer is the same. So chained
| requests, with API.REQ.1 to Server 1 and API.REQ.2 to Server
| 2 will actually work. Maybe session mechanics will work, but
| what if you don't actually have a session and just a bunch of
| API requests?
| andrewmcwatters wrote:
| Querying a database for a session id isn't elaborate work.
| It's also trivial because as TFA mentioned, literally every
| major web framework ecosystem with has a solution for this.
|
| God, how hard is SELECT * WHERE ..., seriously.
|
| You need to share a session across websites? Wow! Connect
| to the database holding the sessions.
|
| Boring.
| jupp0r wrote:
| Ever heard of speed of light? If you really think that
| "just connect to the same db" was an easy solution to the
| problem you describe in the general sense then you
| haven't done so in a moderately complex system yet. It
| can be a good solution for a very limited set of
| circumstances, but that's about it.
| andrewmcwatters wrote:
| It's bullshit. A majority of high volume systems can do
| this just fine. This is just engineering wank.
|
| Standard solution is query a session table on from a
| single location, and once you actually start to need to
| trim request time, it's not even the first place you
| look.
| jupp0r wrote:
| Assumptions you are making:
|
| * everything is located physically close together (good
| luck reading from a DB table in Singapore from a service
| in Europe for every request)
|
| * you have few enough client services that want to do
| this that the number of db connections does not become a
| problem (this is 100 by default for Postgres, you might
| need to tune this or deploy proxies, etc)
|
| * high availability is already taken care of (you don't
| want that one DB server to bring down everything in case
| of a failure)
| nicoburns wrote:
| You have to be pretty big before "store the session
| information in Redis" doesn't work anymore.
| bitexploder wrote:
| And most of these session mechanisms are easy to work with
| as middleware in common web app frameworks making it pretty
| simple to stick with simpler sessions if everyone can get
| to the session store. Everyone way over complicates authn
| and sometimes barely even think about authorization. I have
| seen many a web app with poor JWTs implementation and
| abusable authz get broken. Sometimes the apps warranted the
| JWT implementation but it is a lot harder than many devs
| think.
| zaat wrote:
| That was a battle I fought with some developer
| consultancy not long ago. I won't tell the whole story,
| but I will say that if you have issue with JWT tokens
| that are too big due to the number of groups each user
| have, you probably do need to use JWTs and you are most
| definitely doing it wrong and should educate yourself or
| bring a consultant who at least get the difference
| between authentication and authorization.
| keredson wrote:
| or you have crappy code that can only handle a dozen RPS.
| [facepalm]
| nicoburns wrote:
| I mean, if anything this just means that session storage
| won't be your bottleneck.
| jupp0r wrote:
| Or just have infrastructure that needs to validate the
| session in different parts of the continent (world).
| seabrookmx wrote:
| As far as system load sure. Not so much uptime.. keeping
| your session in Redis creates a single point of failure.
| HA/Clustered Redis exists but definitely has some
| associated complexity.
| closeparen wrote:
| Why would there be any relationship between user sessions and
| microservices? Are you exposing them directly to the internet?
| Illniyar wrote:
| It's pretty rare to have more then 1 client facing API even for
| large apps. Whether it's a monolith, an API gateway, Apollo
| federation or whatever.
|
| What you do to authenticate between the BFF (for lack of a
| better name) and other services is a different matter.
| unscaled wrote:
| > 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.
|
| JWT makes it possible to distribute the same access token
| across multiple systems, but so do stateful tokens. The
| security implications when you're using JWT for this solution
| are much higher than with database tokens. Let's look at this
| for a moment:
|
| JWT Security Issues:
|
| - Inherent design issues (alg=none, algorithm confusion, weak
| ciphers like RSA)
|
| - Cannot be revoked.
|
| - Key rotation and distribution is necessary to keep token safe
| over a long period of time
|
| - Claim parsing needs to be standardized and enforced correctly
| in all services (otherwise impersonation is possible)
|
| Database Tokens Security Issues:
|
| - Timing Attacks against B-Tree indexes [1]
|
| - Giving direct access to the database to all microservices is
| risky
|
| The security issues with databases are ridiculously easy to
| solve: To prevent timing attacks, you can just use a hash table
| index, split the token into a search-key part and a constant-
| time-compare part or add an HMAC to your token. To prevent
| direct access to the database by all your microservices, you
| just wrap it with an API the verifies tokens.
|
| The JWT security issues are much harder to solve. To prevent
| misconfiguration or misuse and standardize the way claims are
| used across your organization, you probably need to write your
| own library or deploy an API gateway. To counter the lack of
| revocation support, you either need to use very short lived
| access tokens (so your refresh token DB will still get a lot of
| hits and you would still need to deal with all the scaling
| issues) or set up a distributed revocation service (not easy at
| all). Setting up seamless key rotation also requires additional
| infrastructure that is not part of the hundreds of JWT
| libraries out there.
|
| It's really easy to get a JWT solution that just works and
| scales easily, but if you really care about security --
| especially if you care about security! -- JWTs are not
| necessarily easier than stateful tokens. They're probably
| harder.
|
| > 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.
|
| Last time I checked (which was today for Google), neither
| Google, nor Facebook is using JWT for their access or refresh
| tokens. The only place I saw JWT with the ID Token in their
| Open ID Connect Flow, and they can't really avoid that even if
| their wanted, since this is mandated by the spec.
|
| Facebook and Google don't need JWT. Scaling and distributing a
| read-only token database to handle a large amount of traffic is
| easier -- not harder! -- for these companies. Stateless tokens
| can be useful for them in certain scenarios, but even then, if
| you're at Google or Facebook's scale, why would you opt for JWT
| over an in-house format that is smaller, faster and suffers
| from less vulnerabilities?
|
| [1]
| https://www.usenix.org/legacy/event/woot07/tech/full_papers/...
| sverhagen wrote:
| I don't think keys need to be distributed per se, rather made
| available at a URL that can be served by the same service
| that issues the tokens? You could call that distribution, but
| that's probably not what you meant. I agree that a lot can go
| wrong, but isn't that also true for home growing a
| distributed database tokens solution (I surely have seen some
| monsters in the wild). So can't the problems with both
| solutions be mitigated using some good libraries?
| unscaled wrote:
| "Made available at a URL" is one possible distribution
| mechanism, yes. But this only works for asymmetric keys. If
| you publish symmetric keys (e.g. for HS256) at a shared
| URL... Well, now everyone can get these keys and forge
| tokens to their heart's content.
|
| Even with asymmetric tokens and a key distribution URL, you
| still have to make sure the clients periodically update
| their list of keys -- this is not something you get built-
| in with every JWT library. And you still have to setup a
| mechanism for generating the keys and distributing them
| between the various instances of your auth server. This is
| not so hard nowadays with cloud KMS services, but setting
| up this solution on our own infra was quite painful.
|
| > I agree that a lot can go wrong, but isn't that also true
| for home growing a distributed database tokens solution (I
| surely have seen some monsters in the wild). So can't the
| problems with both solutions be mitigated using some good
| libraries?
|
| My point is not that a database solution is without its own
| issues. At my $DayJob we're also using a mix of stateful
| and stateless tokens (with distributed revocation lists)
| and we had to deal with issues with both of them. But
| stateful tokens on a database rarely suffer from security
| issues -- the issues we had were always related to
| scalability and performance. The mitigations for these
| issues are also different: they almost always have to do
| with optimizing the infrastructure (scaling out the
| database, adding a cache) rather than using a library. In
| fact, when we use stateful tokens in a distributed scenario
| (and I'm sure this is true for almost everyone out there),
| all token handling is centralized in the auth service, so
| libraries are not strictly necessary. At most, client
| libraries would be very thin wrapper around HTTP API calls.
| pojzon wrote:
| Just use elasticcache for sessions duh. Its a very very old
| pattern.
| likis wrote:
| Agree, and he even mentions in the article "If you process less
| than 10k requests per second, you're not Google nor are you
| Facebook."
|
| There is a huuuuuge gap between services handling 10k req/s and
| Google/Facebook.
|
| I think one big upside with JWT that he doesn't mention is that
| if you have some services geographically distributed, then
| having decentralized auth with JWTs is quite nice without
| having to geographically distribute you auth backend system.
|
| So, yes, if you have a monolith or services colocated, or have
| some kind of monolothic API layer, then no, perhaps JWT does
| not make sense. But for a lot of distributed services, having
| JWTs makes perfect sense.
|
| And you don't have to introduce JWT revocation for logout, if
| you have short token expirations, you can accept the risk of
| token leakage. If the token is valid for like 30 seconds or 1
| minute, you would probably never be able to notice that a token
| has been leaked anyway.
| Hendrikto wrote:
| Bearer tokens are simple until you have to invalidate them.
| Then you get all the complexity of both solutions.
| supermatt wrote:
| As per the JWT spec: " Finally, note that it is an application
| decision which algorithms may be used in a given context. Even
| if a JWT can be successfully validated, unless the algorithms
| used in the JWT are acceptable to the application, it SHOULD
| reject the JWT."
|
| There is no reason you can't keep a list of valid "session"
| identifiers and check the JWT is valid against that as part of
| verification. Then the only state you need to store server-side
| is the identifier. You get the exact same benefits of server-
| based session stores without needing to store the entire
| session on the server - just the identifier.
| 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.
| unscaled wrote:
| I'm happy that it works for you, but you've just been lucky.
| Statistically speaking, JWT attacks are far more common in the
| wild than attacks against stateful tokens or other token
| formats (such as PASETO).
|
| The author of this essay even gave us a few example
| links[1][2][3]. Most users of JWT didn't go through a security
| incident, but a large enough percentage did. Far larger than
| you get with any other method.
|
| > It's a well-documented standard
|
| I beg to differ at this point. Yes, the base standard itself is
| well-documented, but a safe way to use it is not. The JWS and
| JWE specify a great many algorithms without recommending which
| one of them is safest to use. Some of these algorithms (e.g.
| most types of RSA in the spec, AES-GCM with KW) are unsafe
| without extra precaution. The also doesn't mandate any claim
| (including the "exp" claim!) and does not mandate setting up
| key ids (which are necessary for key rotation).
|
| If you need to encrypt your token contents the standard also
| doesn't help you: It just gives examples of how you'd use an
| unauthenticated encrypted JWT[4] or a "sign-then-encrypt" JWT-
| in-JWE with RSAES-PKCS1-v1_5[5]. I cannot stress this enough,
| but _BOTH_ examples in the standards are very obviously
| insecure. The first example has no signature or authentication
| at all (i.e. everybody can forge this "encrypted JWT"), while
| the second example uses a naive sign-then-encrypt scheme with
| the worst protocol for this type of scheme: RSA PKCS #1 v1.5,
| which is vulnerable to Bleichenbacher's attack[6].
|
| If you want to use JWT _securely_ (assuming you 're ok with 5
| minutes access tokens that cannot be revoked and you'll still
| be maintaining a database for refresh tokens), here is what you
| need to do to use it safely:
|
| 1. Use the HS256 algorithm for monoliths or services behind a
| single proxy or API pgateway.
|
| 2. If you want to distribute authentication across multiple
| services without making it possible for the various services to
| generate tokens, use Ed25519 (as per RFC 8037). Unfortunately,
| this is not supported by many libraries out there. ES256 is not
| terribly insecure for signing tokens, but there are enough
| caveats (such as its behavior when the RNG fails) that scare
| me.
|
| 3. Encrypted tokens should be avoided. If you really need them,
| they can only be used symmetricly (i.e. same way you'd use
| HS256). They should be done by embedding a JWE payload inside a
| JWS. The JWE should use alg="A256KW" and
| enc="AES_256_CBC_HMAC_SHA_512".
|
| 4. "exp", "iat" and "jti" claims are mandatory. "jti" should
| include a 64 byte random value encoded as base64url.
|
| 5. "sub", "aud" and "iss" claims are mandatory and should be
| verified.
|
| 6. A "scope" claim containing the tokens scope should be
| included and verified.
|
| 7. A "clid" or "azp" claim containing the Client ID should be
| included and verified, to identify the client.
|
| 8. All keys MUST have a "kid" specified, to allow rotation.
|
| Or you could just use PASETO v4.local/v4.public and get most of
| that work done within the library itself.
|
| [1] https://nvd.nist.gov/vuln/detail/CVE-2024-22513
|
| [2] https://www.howmanydayssinceajwtalgnonevuln.com/
|
| [3] https://auth0.com/blog/critical-vulnerabilities-in-json-
| web-...
|
| [4] https://datatracker.ietf.org/doc/html/rfc7519#appendix-A.1
|
| [5] https://datatracker.ietf.org/doc/html/rfc7519#appendix-A.2
|
| [6] https://datatracker.ietf.org/doc/html/rfc8017#section-7.2
| dudeinjapan wrote:
| Thank you, this is very great advice! We are adhering to most
| of these items today but I will double-check with our
| security team about closing any gaps.
| 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.
| Aeolun wrote:
| > revoke refresh tokens as needed
|
| That's a logout requirement?
| jurassic wrote:
| Not as I understand it. When I've seen this discussed, a
| "logout requirement" has usually meant some stakeholder
| thinks they need a way to prevent previously issued access
| tokens from being used even though the tokens are signed by
| the trusted authorization server and not expired (i.e. still
| valid). This requirement asks that you find a way to
| instantly shut off access even though the auth server has
| previously issued access tokens that should entitle the
| bearer to perform actions against protected resources until
| the token expires.
|
| Blocking refresh in the authorization server is trivial, but
| trying to implement the same on access tokens in the resource
| server at the point of use breaks the entire security model
| of JWT. It's unreliable, because now every resource server
| has to take on partial responsibility for authorization which
| multiplies opportunities for mistakes. As the OP points out,
| you need to keep track of some sort of block list and lose
| out on many of the benefits of JWT (i.e. a resource server
| being able to rely fully on claims in a signed token before
| allowing an action).
|
| When people show up with this kind of requirement, in my
| experience, it is often because they foolishly configured a
| client with a very long expiration on access tokens (e.g.
| ~months/years instead of ~minutes/hours). This creates a
| problem when some aspect of a user's access needs to change
| (e.g. disgruntled employee was fired, customer didn't pay
| their bill, etc). You can address this more easily by pairing
| a short access token lifetime with a long refresh token
| lifetime.
| u32480932048 wrote:
| Yeah, we had a couple customers ask about this, but they were
| ultimately satisfied with dropping the token from the session
| to give the appearance of logging out (so they could log in as
| another user), and just decided to accept whatever risk goes
| along with someone copying the session token, hitting "logout",
| then running cURL commands for 4 more minutes.
| 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
| banish-m4 wrote:
| Do not outsource auth to a third-party. The Okta failure was
| bad enough.
| 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?
| 4star3star wrote:
| Some people advocate for a secure httpOnly session cookie for
| the client, letting the server hold onto the JWT and manage
| refresh. This gets you the benefit of server to server access
| via the token as well as the "session" concept and the warm
| fuzzy feeling of knowing the client doesn't hold the token.
| Savageman wrote:
| Sounds a nice compromise, thanks
| 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.
| whizzter wrote:
| opaque apart from that you should verify that the JWT token
| is issued by a trusted party and fulfills claims that your
| service requires? :P (Unless those parts are handled by a
| library you've configured to check this).
| hnbad wrote:
| The point is that when logging in with AzureAD your app
| needs to talk to AzureAD using OIDC but JWT is an
| implementation detail of that specifically and there's no
| reason this means you need to or should be using JWT
| throughout the rest of your architecture.
|
| If you're using AzureAD for IAM, you're not "using JWT for
| authentication tokens", you're using AzureAD. This isn't
| what the article is about. The article is about building
| your own services that generate and process JWTs. And yeah,
| if you use an OIDC API you likely use an OIDC library
| instead of rolling your own. So as far as your own code is
| concerned the token is entirely opaque.
| osigurdson wrote:
| Wouldn't an app normally at least need to look at some claims
| in the jwt (email for example)? Otherwise, how do you
| identify the user?
| hnbad wrote:
| By using the token to access the userinfo endpoint of the
| OIDC API? Yes, some info is encoded in the token already
| but that's why OIDC includes that endpoint unlike OAuth2
| (which was authorization only even if it was often used for
| authentication).
| 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.
| teliskr wrote:
| Some people get entirely too dogmatic about their "XYZ is wrong,
| don't do it!" beliefs. At the time I implemented JWT in our
| system, many years ago; it was the most straightforward way to
| solve the problems that I had. I read about the pitfalls and have
| yet to experience any of them. So in short.. "no regrats" from
| this heathen.
| hot_gril wrote:
| Isn't JWT's main benefit being a standard interchange format? 3
| parts: header, payload containing user info, signature from
| whatever authenticated the user. Can be encoded for URLs and
| decoded to JSON. Seems pretty innocent to me.
| apatheticonion wrote:
| I typically use a service like AWS cognito (using their built-in
| hosted UI) to handle authentication for my apps. That gives me
| MFA, Google/Facebook login, email verification, etc for free and
| has a generous free tier.
|
| I have a template that's backed by terraform and the
| authentication client is in lambda so the whole thing is
| serverless, self-contained and practically free. So I just run
| "terraform apply" and I have scalable auth for my new service.
|
| https://github.com/alshdavid/template-cognito (only 1 dependency
| on AWS, everything else is stdlib)
|
| If any service I create is lucky enough to break out of the free-
| tier and cost is an issue, then I can just move to another
| OAuth2/OIDC provider. The auth mechanism Cognito uses is just a
| specification meaning I am not coupled to any one service
| provider (though the user accounts themselves are). Cognito,
| Auth0, IdentifyServer, or whatever - I can migrate if cost
| becomes a problem.
|
| The big issue with JWTs are that, if lost, they give permissions
| to attackers without revocability.
|
| For this reason, I keep auth-tokens short lived and refresh them
| often. Refresh-tokens are revocable and live for a few days. This
| means that a lost auth-token is only harmful for a few minutes
| while a lost refresh token is only harmful until revoked or
| expired.
|
| Tokens are stored as path-specific http-only cookies so the only
| vector for attack is if a user physically opens devtools and
| gives an attacker the token - or if the attacker has access to
| the computer (physically or via a malicious terminal script).
|
| High risk operations (e.g. delete account, delete content,
| anything high risk) requires "step-up" authentication - so a user
| is asked to re-authenticate in those cases.
|
| Overall, when you consider that rolling your own authentication
| comes with the liability associated with holding user data
| (companies must announce a breach to users, etc) - if a service
| provider like Cognito is compromised, you won't be liable or the
| only one affected.
|
| JWTs have security concerns, but on balance, when used with third
| party provider, a sensible configuration and considering the risk
| of rolling your own - they are fine.
| pan69 wrote:
| My take on it is;
|
| JWTs are good for server to server communication (short lived at
| ~5 minutes).
|
| Sessions are for clients (browsers, apps, anything controlled by
| a person) to communicate with a server/api.
| grepLeigh wrote:
| JWT make the most sense for zero trust machine to machine
| authentication, where you might also want to authorize certain
| verbs/actions/roles after confirming the requester's identity.
| For example, I use a JWT-based authentication and role-based
| authorization scheme for a fleet of Raspberry Pis communicating
| with each other on a LAN or network overlay, and also with a
| multi-tenant API on a public internet-facing VM. The Pis manage
| 3D print jobs.
|
| For users/people/apps, I usually rely on session-based
| authentication. Sometimes I need light RBAC at this layer too
| (users, teams, admins, etc).
| 4star3star wrote:
| I'm unconvinced of the author's actual understanding of common
| JWT usage.
|
| Suppose you use Azure. You may have one or more app registrations
| with defined roles as well as apis exposed within the Azure
| config. It's convenient to acquire an access token that can be
| sent to various apis, each of which can accept the token without
| having to worry about session state or really anything to do with
| authentication other than validating the token's legitimacy. If I
| wanted to roll my own security, maybe JWT isn't how I would
| choose to do it, but I definitely don't want to do that.
| jongjong wrote:
| JWT is the simplest and most versatile authentication mechanism
| we have.
|
| I have no idea why there is so much gaslighting about them.
| People keep pointing to implementation complexity, yet there
| exist proven, heavily used implementations for almost every
| language and engine imaginable. That issue is an issue of the
| past.
|
| It is doubly ironic that people try to point to 'complexity' as
| an argument against them when most of them are addicted to over-
| engineered software stacks... JWTs are amazingly simple when
| compared to most other concepts in this industry.
|
| The aversion towards JWT is weird. I used to think it's probably
| because some people got burned badly due to past implementation
| flaws and still hold a grudge... But the sheer persistence of the
| any-JWT movement leads me to think there may be an agenda behind
| it.
|
| How could anyone possibly claim that keeping track of sessions on
| the back end and passing around session IDs is superior? It's way
| more expensive on the database/datastore, adds latency, it's hard
| to scale, you often end up with stale sessions because it's not
| fail-safe (e.g. how to clean up previously active sessions when a
| worker crashes? Especially if you have multiple workers.).
| Session IDs are MUCH more work.
| angoragoats wrote:
| I disagree strongly.
|
| And I'm wondering if you can comment on the points raised in
| the article regarding how you handle logging out with JWTs? It
| seems you've got two options:
|
| 1. Don't implement logging out
|
| 2. Implement logging out by keeping your JWT expiration time
| short (which is probably good practice anyway) and using a
| refresh token to issue new JWTs periodically.
|
| With the latter, you've gone right back to server side session
| storage. So JWTs are just an added (unnecessary, for most apps)
| layer of complexity on top.
|
| Again, all of this was discussed in the article.
| oppositelock wrote:
| JWT's are perfectly fine if you don't care about session
| revocation and their simplicity is an asset. They're easy to work
| with and lots of library code is available in pretty much any
| language. The validation mistakes of the past have at this point
| been rectified.
|
| Not needing a DB connection to verify means you don't need to
| plumb a DB credentials or identity based auth into your service -
| simple.
|
| Being able to decode it to see its contents really aids
| debugging, you don't need to look in the DB - simple.
|
| If you have a lot of individual services which share the same
| auth system, you can manage logins into multiple apps and API's
| really easily.
|
| That article seems to dislike JWT's, but they're just a tool. You
| can use them in a simple way that's good enough for you, or you
| can overengineer a JWT based authentication mechanism, in which
| case they're terrible. Whether or not to use them doesn't really
| depend on their nature, but rather, your approach.
| fefe23 wrote:
| You are confusing simplicity (it's easy to understand and
| straightforward to implement safely) with convenience (I have
| zero understanding of how it works and couldn't implement it
| securely if my life depended on it, but someone already wrote a
| library and I'm just going to pretend all risk is taken care of
| when I use it).
| oppositelock wrote:
| Am I confusing them?
|
| It's not difficult to implement JWT's, the concept is simple,
| however, with authentication code, the devil is in the
| details, and that's true for any approach, whether it's
| JWT's, or opaque API tokens, whatever. There are many, many
| ways to make a mistake which allows a bypass. Simple concepts
| can have complex implementations. A JWT is simply a bit of
| JSON that's been signed by someone that you trust. There are
| many ways to get that wrong!
|
| Convenience, when it comes to auth, is also usually the best
| path, and you need to be careful to use well known and well
| tested libraries.
| jongjong wrote:
| > Now, let's assume you are not Google. Check which of these
| apply to you:
|
| > 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.
|
| A JWT is like a keycard. If a hotel gives you a keycard to access
| your room, the card itself holds the credentials which give you
| access to the room. That's the core principle behind JWT.
|
| If you want to ban someone due to malicious conduct, then you
| need some kind of ban mechanism but this is a concern of spam
| prevention and attack mitigation. You need such mechanism
| regardless of what session mechanism you use. With JWT, you may
| need to do 1 lookup to check the account object (you can keep an
| isBanned flag on the account itself), with regular session IDs,
| you need 2 lookups (1 for the account object and 1 for the
| session object). JWT still saves you 1 lookup... Also, if gives
| you a lot of flexibility. For example, you may be able to keep a
| 'blacklist' in-memory and separate for each worker (that may be
| appropriate for certain use cases); you're not necessarily forced
| to hit a datastore or database as claimed. Banning and spam
| prevention should be seen as a separate concern.
|
| Also, at small scale, there are scenarios where you don't even
| need a blacklist. Maybe your app is being served on an internal
| private network or maybe it's public but it's not so critical
| that you can't wait for 10 minutes or 1 hour (or whatever) for
| the JWT to expire for the ban to take effect. I mean, with the
| physical hotel scenario as an example; your keycard remains
| active until it expires. There are many such scenarios in the
| software industry where a ban doesn't need to take effect
| immediately.
|
| When you need instant blocking for DDoS protection (where
| immediacy of the ban/block really matters), you typically rely on
| IPs, not specific account or session IDs.
|
| > 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.
|
| As above.
|
| > You need additional relationships between the user object and
| other objects in the database. You hit the database on each
| request.
|
| The number of times you hit the database (and the reason for each
| lookup) matters and it's important not to mix up different
| concerns.
|
| > Your service does anything at all with data in the database.
| You hit the database on each request.
|
| This is just a variation which has the same flaws as previous
| arguments.
|
| The author claims that Session IDs provide:
|
| > Greatly reduced complexity. No need to manage a secure jwt
| signing/authentication key
|
| You can provide the auth key as an environment variable when you
| launch the service. This is well supported in all environments at
| any scale including Docker, Kubernetes... anyway, 99% of services
| rely on various secrets like API keys so you need to pass secrets
| as env vars anyway, what's the issue with having just one more
| env var to hold the JWT signing auth key? There is no added
| complexity there as the mechanism for handling such secrets
| already exists in most applications. It's rare to see an
| application which doesn't have secret API keys... You need them
| for payments (e.g. Stripe API), for database API services (e.g.
| MongoDB cloud), Amazon AWS, etc...
|
| On the other hand, managing sessions on the back end requires
| weird workarounds like setting and constantly refreshing expiries
| on the session keys or running complex cleanup cron jobs because
| you end up with complicated situations where your worker might
| crash and leave behind stale sessions. Session IDs are much more
| complicated.
|
| Not to mention that session lookups becomes a single point of
| failure and can become a bottleneck for your application as you
| get more users. It's really difficult to scale well. You're going
| to run a Redis cluster just to manage sessions? Hello LATENCY!!!
| Welcome DDoS headache!!! Did anyone say backpressure issues???
| How are you going to clean up stale sessions when a worker
| crashes? Good luck.
|
| I hope you're billing for your development work by the hour, coz
| you're gonna need a lot of those! I hope your health insurer
| covers Panadol! Don't be surprised when GlaxoSmithKline opens up
| a new factory next to your office.
| angoragoats wrote:
| > Not to mention that session lookups becomes a single point of
| failure and can become a bottleneck for your application as you
| get more users. It's really difficult to scale well. You're
| going to run a Redis cluster just to manage sessions? Hello
| LATENCY!!! Welcome DDoS headache!!! Did anyone say backpressure
| issues??? How are you going to clean up stale sessions when a
| worker crashes? Good luck.
|
| I think this is pretty far-fetched hyperbole. How do you think
| websites managed logging in before JWTs existed roughly a
| decade ago? They used databases and in memory caches, which
| work fine up to a surprisingly large number of users.
| menacingly wrote:
| We don't use JWTs because we think we're google scale, we use
| them because they're kinda cool. Cheap, stateless auth across
| services is really handy. If I rolled my own solution, it would
| just look like a shitty jwt.
|
| There are definitely arguments to me made against ridiculous
| over-engineering, modern web dev has taken the problems of 1% of
| engineers and made them problems for 100% of engineers, but I
| think this is a bit of a silly one to focus on
| j16sdiz wrote:
| We don't use JWT because we are NOT google scale.
|
| A centralized database for sessions, and we can extend/revoke
| any token anytime.
| rezonant wrote:
| What's interesting about this argument is that nothing is
| stopping you from doing this same thing using JWTs. Just
| generate your token and store it as a claim in the JWT. You
| can check the revocation of the stored token without even
| validating that the token is genuine, if that is fortuitous.
| What this buys you is the ability to attach clear text
| information with the token, and, if you are doing asymmetric
| validation, the ability to validate both the security
| credential and the included plaintext information in an
| untrusted (client side) setting.
| menacingly wrote:
| I actually think the revocation argument is the over-
| engineering case here.
|
| I'd argue that people who need to avoid hitting their
| database on every request outnumber people who need sub-
| minute revocation
| hot_gril wrote:
| I don't see how this solution means you cannot use JWTs.
| jankboy wrote:
| Yes if the JWT token can only become invalid based on an
| expiration time. You can add the expiration time in the token and
| check it during authentication.
|
| No if the token can become invalid due to other reasons because
| lets say the user deletes the token because it got leaked. But
| since you have no way of invalidating the token other than
| changing the encryption key, you can't selectively invalidate
| that one token.
| rezonant wrote:
| Since JWTs can't handle revocation on their own, the main benefit
| (other than the ability to do validation without a central
| authority) of JWTs over opaque tokens is the ability to embed
| data that an untrusted holder (ie client) can make use of. For
| example, attach the display name of the user and their avatar
| profile, so that even after the token expires the application can
| represent to the user who the token is (could be used for example
| to show a "Sign back in, Tom" view). This makes a Switch User
| feature very elegant to implement: the application need only
| store the signed authentication tokens, and those tokens are self
| describing.
|
| Additionally, when using asymmetric validation, you can rely on
| JWTs as licenses: Your software can restrict offline features
| based on a locally stored token, simply by checking that the JWT
| was signed by the authority. In tandem with the ability to store
| metadata, your app (with code held by the untrusted user) can use
| the token to determine the user's license features without
| requiring an always on connection. (Obviously patching out the
| license checks is another matter)
|
| These features can be layered on top of opaque tokens, but since
| a JWT has all the benefits of an opaque token (store the opaque
| token as a claim just like the rest of the metadata), it's
| actually a complete package that does it all without needing to
| roll it yourself.
| cryptonector wrote:
| > Since JWTs can't handle revocation [...]
|
| Revocation is just hard. Even PKI's CRLs/OCSP don't have a
| subscription mechanism by which an end-point can get
| revocations of some small set of certificates. Even a public
| feed of revocations could be problematic if you're going to
| terminate employees because the timing has to be perfect: too
| early and you're tipping off employees, too late and you're
| allowing disgruntled employees run malware on your systems and
| network. In practice being late to revoke access is generally
| accepted as acceptable as long as it's not too late.
| shermantanktop wrote:
| So what's "Facebook scale"? Is there an edge TPS number? Number
| of discrete major services? If you are consistently doing 10TPS
| on 3 services, sure. But many systems are bigger than that.
|
| Everyone wants to be big. You can either frontload those
| problems, and risk drowning in irrelevant complexity, or defer
| them. The problem with deferring is that switching lanes appears
| like it will be expensive and time consuming.
|
| The secret is that if you solve actual problems, rather than
| dreams and future hopes, the answers are almost always obvious.
| The work may be painful and people may be angry, but the
| rationale will be clear.
| abalone wrote:
| I see a flaw in the argument. He shifted from saying you'd use a
| 5 minute access token timeout to querying the DB on every
| request. There can actually be a big difference between those two
| scenarios. Some web APIs can be bursty. Even caching credentials
| for 5 minutes could take significant load off the DB.
| rezonant wrote:
| I'm pro JWT, but reducing load on the DB itself isn't a massive
| argument in favor of JWTs, because an opaque token solution can
| simply cache the result of a revocation check at whatever time
| interval is comfortable for the use case of the token. So
| assuming the API has access to a cache layer, there isn't a
| difference there. If there is no cache layer, there probably
| should be.
|
| In a hyperscaler situation things are different, but we should
| avoid treating that as the norm.
| ahasani wrote:
| While mignt not agreeing with all the reasons mentioned,
| verifying signature for every resource access is cpu intensive
| (your commercial compute provider would love you though).
| Comparing session id to a map is cheap. For me jwt to
| authenticate and random session token for resource access,
| problem solved
| crunchybeeftaco wrote:
| I'm confused though. JWT isn't hard to configure. Why not just
| use it?
| ruszki wrote:
| I don't understand this article and thread either. Using OpenID
| is not rocket science. You can start to use it in matter of
| minutes. The question should be rather why you should care at
| all to use anything else at this point.
| begueradj wrote:
| The article completely ignores single page applications where
| these JWT can be needed a lot.
| redwoolf wrote:
| I keep reading criticism of JWTs that involves impersonation or
| replay attacks. With JWT (or non JWT bearer tokens) you use a
| refresh token. It seems to me that if an attacker gets a JWT they
| also have the refresh token. So how are JWTs inherently more
| insecure than other authentication methods? Almost all data
| passed over the wire nowadays is TLS encrypted.
|
| In my projects, we have used encrypted JWTs and it seems to me a
| fine solution. Log out can be implemented in a user facing client
| by deleting the JWT and refresh token. Given a short enough
| expiration time, this is sufficient for most use cases involving
| user facing applications. Isn't it? Generally, at least in the
| domains of the applications I've worked on, users only intend to
| log out of their current application when logging out. Meaning if
| they are signed in on their phone and on their desktop browser,
| when they sign out in the browser they don't intend to also log
| out of their phone application.
|
| The only downside I see is that if you want to log out of all
| sessions it is impossible to implement without maintaining
| session state in the server.
| mikeryan wrote:
| _It seems to me that if an attacker gets a JWT they also have
| the refresh token._
|
| No they don't. JWTs can be used with third party services that
| should never see a refresh token. Those are the requests that
| should be presumed vulnerable.
| redwoolf wrote:
| I've not come across such a use case as I've only ever
| written applications where we own both the service and the
| clients. Thanks for the explanation.
| cryptonector wrote:
| > So how are JWTs inherently more insecure than other
| authentication methods? Almost all data passed over the wire
| nowadays is TLS encrypted.
|
| JWT's security -and that of _all_ bearer token systems- depends
| utterly on the use of TLS.
|
| The security of JWT used correctly is comparable to that of
| Kerberos or PKI. There are some things to look out for, like
| that it's way way too easy to write implementations that fail
| open (e.g., you don't recognized a signature algorithm so you
| don't validate the signature but also fail to fail), but other
| than that there's nothing particularly bad about JWT.
|
| > Log out can be implemented in a user facing client by
| deleting the JWT and refresh token.
|
| Logout has to be implemented either by letting time pass w/o
| re-authenticating (i.e., let the session expire) or telling the
| server that you're logging out. You can login again, even with
| the same token as before (IFF it's not expired yet). There is
| no reason to have to "burn" a token, and that would add a
| significant amount of complexity akin to revocation.
|
| > The only downside I see is that if you want to log out of all
| sessions it is impossible to implement without maintaining
| session state in the server.
|
| Sessions imply session state. What you probably meant is that
| if you want to revoke access then you need a revocation system,
| and that effectively bolts on extra state on your servers (and
| a pub/sub system). Generally no one wants that headache.
| unscaled wrote:
| Here's the thing: neither Google, nor Facebook is using JWT for
| their access or refresh tokens. The only place they use JWT, as
| far as I know, is for the ID Token in their Open ID Connect Flow,
| since this is a mandatory (and terribly misguided) part of the
| spec.
|
| I keep seeing the idea that JWT was designed for Google or
| Facebook scale being repeated over and over, but the reality is
| that neither company uses it. Last time I checked, both used
| rather short access and refresh tokens and it appears that at
| least the refresh token (if not both) is stateful.
|
| Implementing stateful tokens on a global scale and sharing them
| across hundreds of service is HARD, but it's easier when you are
| Google or Facebook, and you've got enough resources to throw at
| this trouble.
|
| And if you do need to implement a stateful token, you've got
| every reason to choose your own format. Your applications are
| using your own authentication libraries and infrastructure (e.g.
| API gateways), so you don't have to worry about complicating
| their life with a non-standard format. The upside for using your
| own stateless format is that you avoid all the design issues with
| JWT (alg=none, algorithm confusion, questionable support for
| outdated algorithms from the 1970s) and you can design a far more
| compact format that takes a fraction of the size of JWT[1].
|
| There's a reason JWT got popular with scrappy startups,
| enterprises hobby projects and Udemy/Medium tutorial authors:
| they're very easy to spin up and library support is everywhere. I
| don't mean to say JWT is the right choice for any of these uses
| -- it probably isn't. But it's the easy choice, the worse-is-
| better solution. The worse solution needs only be better in one
| respect to win: it should be easier to implement, copy and
| spread.
|
| In the end of the day, JWT is not a good solution for either
| Google-scale companies or small startups. But it's the small
| startups that usually lack the resources and awareness to adopt
| another solution.
|
| [1] https://fly.io/blog/api-tokens-a-tedious-survey/#protobuf
| Joel_Mckay wrote:
| In general, a breadcrumb or cookie with symmetrically encrypted
| session UUID, epoch time, IP, and transaction counter is wise.
| You should also permute the servers hash salt with date daily to
| boot session campers.
|
| If for some unknown reason the recovered client transaction
| counter losses its expected position, than you know someone has
| tampered with the session, and or stolen your clients session
| token.
|
| Donate to the FOSS project of your choice if you find this
| useful. =3
| devdiary wrote:
| Start with usual session based authentication. Keep it until you
| see the absolute need to move to JWT. And make sure you
| understand JWT and "invalidating JWT" before using it -
| https://github.com/gitcommitshow/auth-jwt?tab=readme-ov-file...
| nine_k wrote:
| Yes. I mean, no; you should use macaroons [1] instead, which are
| better than JWTs but are built on similar ideas.
|
| [1]: https://fly.io/blog/macaroons-escalated-quickly/
| axelv wrote:
| What about jwt's in a session cookie? I think the whole story
| needs more nuance. JWT's have many purposes.
| alex_young wrote:
| "No."
|
| Whenever I see such a simple answer to a complex question, I know
| it's probably an oversimplification.
|
| The real answer is a solid "it depends on what you want to
| achieve."
|
| Say you handle invalidation by maintaining a cached table of
| revoked tokens. Is this table larger or smaller than the table of
| all users?
|
| Perhaps you would like to embed some RBAC info in the token. Is
| validating both the token and it's absence from your revocation
| table more efficient than looking up all of the other
| information?
|
| Perhaps you need to do this on a distributed basis. Is the
| overhead of maintaining such a table more or less than making all
| the DB calls and creating a central choke point in your
| architecture?
| DeathArrow wrote:
| I don't get why he is pretty sure everybody has only one database
| which stores user data and application data. At work we have user
| data in Keycloack and application data in at least 20 different
| databases.
| hansoolo wrote:
| Off topic: the domain name is great!
| 1penny42cents wrote:
| It's a great analysis but I think it's too either-or.
|
| If you have a monolith anyways then yes, why use a distributed
| systems solution like JWT? Completely agree.
|
| But if you already have an auth service, making it optional for
| the majority of requests is a distributed systems win. Even if
| you need to implement forced logout or some other features which
| require hitting the auth database, they can be optional requests.
| If the auth service is available, you get better security,
| otherwise the services can decide whether to continue or not.
|
| This is better than your entire app going down or slowing down
| with the auth service. Though the refresh token bit is still a
| challenge, it's a smaller one than a hard dependency on the auth
| service on every request.
|
| Again, if your auth service is just a component in your monolith,
| the author is completely right. It's context-specific.
| vldb7 wrote:
| I don't think it is either-or type of choice. A lot, if not all
| arguments against that use of JWT disappear if you're ok with
| compromise solution: user management actions will take time to
| propagate. If JWT lifetime is 5 mins, it means that all actions
| like logout, deactivating account etc will take 5 mins to
| finalize - and you'd be hitting the database exactly once per 5
| mins for the purpose of checking if user is still active, refresh
| token is not barred by log out etc.
| koliber wrote:
| Nothing wrong with JWT bearer tokens as a technology.
|
| However, too many times they're implemented incorrectly or
| without forethought. I've seen a few teams who used the bearer
| token, set the age really high, and never bothered to implement a
| refresh mechanism.
|
| Fast forward a few months and someone says it is not possible to
| log someone out of our service.
| winternewt wrote:
| Without JWT, how do you support log in using third party identity
| providers like Office 365, Google or Facebook?
| ChicagoDave wrote:
| The JWT has some extra fluff for the client, but only the Bearer
| token is used for secure communication. And every call to an API
| validates the Bearer token with an identity service. There is no
| automatic security because you have a token. That Bearer token
| (not the JWT) must clearly be validated and also validated with
| whatever functionality (Claims) is potentially being requested.
|
| The meta data in the JWT is sort of a short cut to let the front-
| end make assumptions, but it has no bearing on the actual
| capabilities. Only a valid Bearer token can determine if a call
| is secure (authenticated) and has the correct permissions
| (authorized).
|
| So, you don't need a JWT, but without it, you're still going to
| need a way to send mundane meta data back to the front-end. This
| used to be (and still can be) a separate call for "config" or
| "permissions" data, but why bother. Just create claims in your
| identity server, mark your API's with those claims and token
| validation, and you're in great shape.
| gizzlon wrote:
| Changing the JWT because the frontend suddenly requires "middle
| name" is a PITA. Also, the JWT can become become large.
| datarez wrote:
| The main advantage of jwt is that is stateless, so it reduces
| load on database and or caching layer when checking user session.
| Alongside being able to share the public key to verify the token
| across different services
| tracker1 wrote:
| Authentication is often the first thing I want to break out of
| the application and backend anyway. Good password hashing is
| expensive... Why should an entire application have to go down
| when your login is being DDoSed?
|
| More so, A revocation list on something like Redis can expire
| with a token and a lot less expensive than an rdbms lookup with
| joins.
|
| Not too mention, why add extra load with extra DB calls in the
| first place?
|
| You don't have to be Google scale to want to separate logins from
| the main service. And that's just for starters.
| mstaoru wrote:
| JWTs are rather convenient for API access, especially for APIs
| that are hit at high req/s rate, as they allow to decouple auth
| check and actual request processing. In more complicated cases
| you can use JWT subject for some simple preflight ACL checks as
| well.
| PaulHoule wrote:
| Here is a quote from a comment in that article:
| I feel like this subject comes up every couple of months
| with another iteration of why people think JWTs are bad.
|
| The regularity which with this subject comes up makes me think of
| how Triplebyte used to pay off bloggers in the day to write posts
| with the title "hiring is broken". I don't have the proof but I
| am picking up a bad smell here.
|
| Gotta be _yet another_ of the vendors which is selling some
| authentication system that they host. I remember trying to
| promote an open source user management system in the early 2000s
| and nobody cared until they added killer feature "our service
| will get shut down when we get acquired" which somehow drew the
| pointy haired boss like a moth to a flame.
| stanac wrote:
| 1. You can set JWT as cookie value, I think author is describing
| OAuth 2 problems, not JWT problems. Interestingly JWT is not
| mentioned in OAuth 2 spec [0].
|
| 2. JWT doesn't have to contain user details, it can be a simple
| reference token used for introspection [1]. This approach removes
| problems with invalidation and logout since identity service
| should store invalidated tokens.
|
| 3. JWT can contain refresh token id (or hash) and check for
| invalidated refresh tokens in (distributed) cache. Cache entry
| should not be long lived, and refresh token shouldn't be long
| lived if you are using proper refresh token rotation with family
| invalidation in case of a leak.
|
| That being said cookies are still simplest and safest bet for
| simple monolith applications.
|
| [0] https://datatracker.ietf.org/doc/html/rfc6749
|
| [1] https://datatracker.ietf.org/doc/html/rfc7662
| blntechie wrote:
| I have used OAuth2 with and without JWTs as bearer tokens and
| pretty much used them the same way. JWT helps with fetching the
| user details without having to hit the DB/backend, and that's
| basically was the only difference to me.
|
| I believe the issues he is describing is more OAuth2 rather than
| JWT.
| cryptonector wrote:
| This is a bit nonsensical. Using the same logic regarding
| logout/revocation you would also be opposed to using Kerberos,
| say. So let's discuss the whole logout/revocation case.
|
| In a typical Windows/AD or Unix installation you might have
| Kerberos (definitely in the Windows/AD case, possibly in the Unix
| case) _and_ a directory (definitely in both cases, though in the
| Unix case it might be purely local), and you use the
| authentication system (Kerberos, say) in such a way that it
| allows you to elide some directory lookups on Windows /AD or not
| at all on Unix. Either way you get a worst-case latency for
| revocation of the user's service ticket's lifetime (Windows) or
| whatever you do to stop locked user processes (Unix). Well,
| that's the theory, but in practice many SSHv2/whatever
| implementations do not force session end at ticket expiration. So
| Windows/AD uses group policy for revocation. On the Unix side...
| we don't really have a standard solution, but essentially one can
| build a daemon that periodically looks for and kills processes
| running as now-locked users.
|
| (For SSHv2, if you build re-authentication into a KEX, like GSS-
| KEX does, then you can force re-authentication and session end
| when authentication expires. In practice on Unix systems it's not
| really possible to elide a directory, so this is not necessary.)
|
| Now for HTTPS apps it's a different story. You can use cookie
| expiration and force re-authentication so that revocation latency
| is bearer token lifetime, then keep bearer token lifetimes short.
| If you don't control the token issuer then you can still impose a
| shorter cookie lifetime in your app and demand a fresh token when
| you force re-authentication.
|
| In any case, one does not need a revoked token/ticket/whatever
| list!
|
| But it _is_ true that bearer tokens don 't completely elide the
| need for a directory for things like SSH logins onto hosts. But
| they do for HTTPS apps.
|
| So I think TFA is just wrong.
| jmartrican wrote:
| I worked in a backend team that introduced JWT, before I got
| there. The problem we had with JWT was that the data was stale.
| Even if it wasn't stale, it needed to be treated as stale because
| every service wanted the up to date data, even within 1 sec that
| data is old. The user could have changed something in their
| account from the time that the JWT was issued. I removed JWT and
| went back to the old UUIDs as tokens.
| dwhitney wrote:
| oof - this article is pushing bad advice - general disclaimer:
| use a third party authentication system like Okta or Cognito.
| It's going to save you so much grief down the road. They pretty
| much all use the same pattern (OIDC), so you just need to learn
| it once, and you're good for at least another decade.
| Authentication is one of the easiest and most important things to
| take off of your plate. Do it.
| skywhopper wrote:
| This article has a pretty narrow view of what uses a JWT can be
| put to. Yeah, in his limited examples, JWT is overengineered. And
| for non-distributed systems, JWT is overengineered. But there are
| plenty of use cases where JWT can simplify things and minimize
| complexity. Eg, when network connectivity is restricted and the
| consuming service cannot talk to the issuing service. Or when
| using a single token to auth against multiple remote systems. Or
| when latency is high between the central auth system and the
| consuming service. Or when you don't have tight TTL/revocation
| concerns and you just want to auth once a day or week. Or when
| you just need a one-time token to establish some other service
| relationship. Or when you want to scope down permissions to
| subsets of what's possible, or embed arbitrary auth metadata into
| the token, JWT has solutions for you.
|
| But if you just think of this author's narrow view of what system
| designs look like, then skip the JWT.
| benced wrote:
| I like the idea of using JWTs as opaque tokens. It sets you up
| nicely to migrate to using them semantically and there's very
| little downside (you just need a JWT library where the tokens are
| minted and then it's just string equality everywhere else) if you
| never actually end up using JWTs.
| nu11ptr wrote:
| The article is just as wrong as articles that say you should use
| JWTs. They are both wrong because they lack context, at least in
| their opening. Interestingly, the article eventually does give
| context, but saying "it depends on what you need to do"
| apparently doesn't get as many clicks as starting by saying "no".
|
| For the record, I use JWTs, I have hardly any scale at all. I
| have none of the requirements that would hit the database on each
| request. It works just fine and I didn't need to consult an
| article to tell me what to think because, and this is the crazy
| part I know, I'm able to break apart my business requirements and
| decide for myself what is needed (or not). JWTs work just fine in
| my case. YMMV.
___________________________________________________________________
(page generated 2024-05-28 23:01 UTC)