[HN Gopher] JWT vs. Opaque Tokens
       ___________________________________________________________________
        
       JWT vs. Opaque Tokens
        
       Author : fabig
       Score  : 118 points
       Date   : 2022-09-29 09:18 UTC (13 hours ago)
        
 (HTM) web link (zitadel.com)
 (TXT) w3m dump (zitadel.com)
        
       | rubyist5eva wrote:
       | Don't roll your own JWT implementations for client side
       | applications, for the love of dog don't.
       | 
       | Story time.
       | 
       | Our company recently switched to JWTs for our SPAs from regular
       | OAuth2. I told them up front - we need a way to invalidate a
       | token if an account is compromised. The lead on this initiative
       | said we can blacklist any token. I told him that's not practical
       | because you would need to know the exact token to be able to
       | blacklist and because we don't store them in the database and
       | don't log them have any real way to figure out which token is
       | being used by an attacker and which are not that it's basically
       | useless.
       | 
       | I suggested a simple fix: cypher the private key we sign the JWT
       | with the hashed password of the user account we're generating the
       | token for. If an account is compromised, we can reset the
       | password and invalidate all tokens for that one user.
       | 
       | I was ignored and lo-and-behold within a month CTO and tech lead
       | are trying to track down JWTs for a hacked account. I told them
       | we can update the app to cypher the key, it'll invalidate all
       | tokens and people will have to log in again but at least they'll
       | be secured. Nothing has been changed to this day, despite banging
       | this drum for literally over a year. We've recently extracted our
       | authentication into a micro-service (for no reason really, i'm
       | still mad about this too) and still nothing has been done about
       | this issue when it would have been the perfect time to fix this.
       | 
       | I love my job but "priorities" and "business cases" as an excuse
       | for this kind of incompetence is rage inducing.
       | 
       | The point I'm trying to make is. You are most likely using some
       | kind of web framework that can just plug in an authentication
       | implementation, just use that. NIH is very real and it is more
       | than a waste of time, it can be dangerous.
        
       | mooreds wrote:
       | Full disclosure, I work for FusionAuth, a competitor of Zitadel
       | in the auth server market. Our software issues a lot of JWTs.
       | 
       | I agree with the premise of the article, which is that JWTs
       | aren't the right answer for every solution. Ine pattern we've
       | often seen to mitigate some of the issues of JWTs is to store
       | them serverside, in a session. Now you get all the benefits of
       | session management (revokability, single view of usage) but can
       | still present a JWT to other APIs if needed.
       | 
       | I'd never put sensitive data in a signed JWT. In fact, at
       | FusionAuth, even JWT claims like the user id is a UUID, just so
       | you don't inadvertently leak information like "how many users are
       | there" via an integer user id.
       | 
       | The main reason why JWTs work so well is their statelessness. By
       | that I mean the fact that you can verify their integrity without
       | "calling home" (especially if you've set up asymmetric keys
       | correctly). In this case, you don't have the same availability
       | and scaling requirements for your server that issues JWTs that
       | you would for a server that was responding to opaque token
       | requests.
       | 
       | It's from last year, but I compare and contrast these two
       | approaches in this video I presented at a meetup, starting a few
       | minutes in: https://youtu.be/rArCF7nUcvY?t=451
       | 
       | JWTs are part of building an app that scales. But like any other
       | scaling choice, it has consequences. Just as you wouldn't shard a
       | database before you need to, you shouldn't build an app that uses
       | JWTs to scale unless you need to. Though switching between
       | sessions and JWTs is going to be an easier transition than
       | sharding vs unsharding a database. Data has inertia and all that.
       | 
       | I don't believe there is much functional difference between
       | sessions and opaque tokens. Both have to be stored somewhere,
       | both require a central source of truth, both require that store
       | of truth to be constantly available. There are differences in how
       | they are managed/acquired, but from an architectural perspective
       | they are similar.
        
         | zhte415 wrote:
         | UUIDs leak information, by definition. For that reason, I'm not
         | a fan. It's just leaking on the other side.
         | 
         | I'll explain: A UUID should be pretty unique in the universe.
         | Wherever it crops up, as there should always be an assumption
         | of the possibility of leaking data and associated data at the
         | same time, whomever the UUID belongs to has had their
         | information leaked. That could be associated meta data in a
         | request like IP address, to a print out that has a user's UUID
         | in the header. In all cases it ties data to an individual.
         | 
         | Better is to just use a high integer that doesn't simply
         | increment, but changes by an amount. But low enough to blur
         | into noise. Heck, this can be rotated.
         | 
         | I stand to be convinced otherwise, but via the reasoning above
         | I believe UUIDs are not desirable for user privacy.
        
           | adamckay wrote:
           | I don't understand what you mean here.
           | 
           | You're saying that because UUIDs can be assumed to be unique
           | in the universe, when it's leaked alongside other data it can
           | then be correlated with other data leaks to tie data to an
           | individual? How does a user ID being `8646846` make it any
           | safer from leaks or correlation than
           | `123e4567-e89b-12d3-a456-426614174000`?
        
         | giancarlostoro wrote:
         | > I agree with the premise of the article, which is that JWTs
         | aren't the right answer for every solution. Ine pattern we've
         | often seen to mitigate some of the issues of JWTs is to store
         | them serverside, in a session. Now you get all the benefits of
         | session management (revokability, single view of usage) but can
         | still present a JWT to other APIs if needed.
         | 
         | This seems weird to me. The whole point of the JWT is that you
         | know with confidence that the client has the data you need and
         | cannot change it. I mean, if it works for them cool, but at
         | that point you might as well just have a session with an ID and
         | a table with all the relevant session information in one swoop.
        
           | mooreds wrote:
           | > The whole point of the JWT is that you know with confidence
           | that the client has the data you need and cannot change it
           | 
           | I would change that to "The whole point of the JWT is that
           | you know with confidence that the client can provide tamper
           | proof data, often identity, to other servers and APIs."
           | 
           | Yes, the OIDC id token is for the client to consume, but if
           | it is an access token, it is for the resource servers (to
           | slip into a bit of OAuth jargon). Put whatever you want in
           | the id token, knowing the client will have full access to it.
           | If it is a javascript or native client, you don't know where
           | that will go, but having it shouldn't grant access to
           | anything privileged.
        
             | jwtbrothrow wrote:
             | > Regarding that last, there's a lot of brainpower put
             | towards edge cases and security in the OAuth working group
             | 
             | This is obviously why people should adopt OIDC.
             | 
             | I don't really get the hate for OIDC. Nothing says "Junior
             | Developer" like posting on Hacker News how shitty this
             | widely adopted, durable technology is, especially by
             | calling it "JWT."
             | 
             | This token expiration boogeyman is especially dumb. If
             | there's a security misconfiguration so disastrous that the
             | user can exploit it in less than 5 minutes (a typical
             | access token lifetime), you're only going to be booting
             | them out of the system after they've done the damage
             | anyway.
        
               | wokwokwok wrote:
               | ...but how do you get the access token every 5 minutes?
               | 
               | Surely not, because, it's be _obviously stupid_ using a
               | refresh token right?
               | 
               | Not a _long lived_ refresh token.
               | 
               | A refresh token... that you might, say, need to revoke at
               | some point?
               | 
               | Somehow.
               | 
               | Definitely a boogeyman. ...because people don't
               | understand how it works.
        
               | jwtbrothrow wrote:
               | > Somehow.
               | 
               | This word, revoke. It appears in OIDC exactly twice. You
               | can look it up yourself. In order to get a new access
               | token, you have to hit an authorization server URL, not
               | an application server URL, with your refresh token. If it
               | was revoked, you'll know then. The authorization server
               | will simply not give you a new access token, and while
               | you have a string of bits still called a refresh token,
               | it is as useless as an old password.
               | 
               | I get that your snark is stylized, and this is Hacker
               | News, and uniformly, the junior developers in my life
               | that I engage with deploy snark, that's all fine. Really
               | the emphasis is on how much the OIDC people have thought
               | about all these things, and while I agree it is a lot to
               | learn, it is in principle the only winning standard for
               | authentication and authorization nowadays, it is what
               | everyone uses, so you might as well learn it.
        
               | P5fRxh5kUvp2th wrote:
               | I suspect cookie sessions is still more widely used than
               | anything approaching OAuth and it's ilk. Hell, even JWT's
               | often get associated with cookie sessions, which helps
               | mitigate the revocation problem.
        
         | wokwokwok wrote:
         | > ...pattern we've often seen to mitigate some of the issues of
         | JWTs is to store them serverside, in a session.
         | 
         | ...
         | 
         | > The main reason why JWTs work so well is their statelessness.
         | 
         | You realise this is obviously a very weak argument for using
         | them? Stateless in a way that is apparently not useful for most
         | people. Great.
         | 
         | I've never seen a serious JWT implementation that didn't use a
         | database to manage lockout and other state related things that
         | inevitably turn up as product requirements.
         | 
         | Once you do, you now have a stupid pointlessly complicated
         | session implementation that potentially leaks sensitive
         | information.
         | 
         | That's the whole point of the article.
         | 
         | If you you need jwt for "other services" issue jwts for them
         | when they become a requirement.
        
           | mooreds wrote:
           | > You realise this is obviously a very weak argument for
           | using them? Stateless in a way that is apparently not useful
           | for most people. Great.
           | 
           | Well, it depends. With JWTs in a session, you get a time
           | bound set of credentials that can be verified server side,
           | with rotation built in and a lot of docs, libraries and
           | experts thinking about things. (Regarding that last, there's
           | a lot of brainpower put towards edge cases and security in
           | the OAuth working group!)
           | 
           | Other sets of users use JWTs in their pure stateless form,
           | often with a short expiration time in a secure HTTPOnly
           | cookie, transparently refreshing often. This offers easy
           | horizontal scaling, as long as you only want to talk to
           | servers in a single domain (you can always proxy calls other
           | domains if needed).
           | 
           | I don't think that JWTs are a magic bullet, but they
           | definitely have some strengths.
        
       | kyrra wrote:
       | It's funny to read about all the web app usage of JWT, and here I
       | am dealing with it server side.
       | 
       | For those unaware, JWT has the 2 ways of encoding it: JWS and
       | JWE. Because of these properties, you can use it how people would
       | use it for application level messaging. If you are already on a
       | secure channel, you can sign or encrypt the message so
       | application level checks can happen.
       | 
       | This makes it act like a replacement of PGP for you paranoid
       | people out there.
       | 
       | (Btw, I recommend against this, and think people should use PGP
       | or Tink, as it's easy to footgun yourself with JWS.)
        
       | tialaramex wrote:
       | An ex-colleague _loved_ JWTs, using them in systems where I 'd
       | argued strongly they were inappropriate, and since I wasn't able
       | to cut holes in the resulting system in a few hours spare time
       | spent tinkering and they really wanted to do it, it went ahead. I
       | guess I at least know they didn't fuck up in any of the obvious
       | ways because I checked those.
       | 
       | Recommended thought experiment: Every programmer who makes or
       | consumes the tokens in your system needs to attend a meeting
       | about the tokens. Picture that meeting in your head. Was it a
       | huge endeavour, involving several hotels and many months of
       | planning? Then you probably need JWTs. If the meeting could
       | happen in a coffee break then JWTs are wildly inappropriate.
        
       | Xeoncross wrote:
       | Session tokens need to be stored on the server (redis, db, etc..)
       | so you can change them, see all devices logged in, and other
       | requests product will have.
       | 
       | They should be unguessable and unrelated to anything. Read 20
       | bytes from /dev/urandom (or whatever stdlib your language
       | provides), create an entry in your store for token->user_id, then
       | put it in a httpOnly + secure cookie (so Javascript can't access
       | it), and send it to the client.
        
       | aaronmu wrote:
       | What's the difference between an opaque token and a cookie that
       | has a single session identifier in it? 'y know - the way we did
       | it in the 90's.
        
         | mooreds wrote:
         | For a normal web app, not too much.
         | 
         | As sibling comments point out, an opaque token can be stored
         | elsewhere (though, to be fair, the session identifier which is
         | in that cookie can be placed elsewhere too).
         | 
         | Cookies are limited in where they can be sent
         | (https://developer.mozilla.org/en-
         | US/docs/Web/Security/Same-o...).
        
         | ffo wrote:
         | The cookies is mainly used to identity the user (e.g. his
         | session and prior authentication), while the tokens are used to
         | forward something to proof that the an application wants to
         | access one or multiple apis.
        
           | tgv wrote:
           | So if you need the client to pass on sensitive
           | (authentication/authorization) information to another party
           | without that party having access to the original provider of
           | that data (except its public key, I suppose). Then JWT is a
           | usable format, with a lot of support.
        
             | ffo wrote:
             | Well, yes ;-)
        
         | cnorthwood wrote:
         | There isn't one - the session identifier is an example of an
         | opaque token
        
         | senko wrote:
         | Cookie is a mechanism to store and send tokens to the server,
         | which is orthogonal to what the token is.
         | 
         | You could store JWT in a cookie, or use opaque token in a HTTP
         | header, for example.
         | 
         | That said, the session cookies we loved back in the day were
         | usually opaque tokens, yeah.
        
       | pmontra wrote:
       | I investigated this issue with a customer recently with a focus
       | on revocation. We concluded that if we have to hit the database
       | to check if a JWT token is still valid we can use a session
       | cookie (or equivalent) and hit the database to get the user, the
       | associated capabilities, etc.
        
         | Awerion wrote:
         | Than you don't need it if you don't see the advantage.
         | 
         | You normally do lots of API requests while you are logged in.
         | To services and to download an image for example.
         | 
         | You make sure the current jwt is valid for a few minutes and
         | hit only the database with the refresh token for example.
         | 
         | Only in worst case you really need to block a token and it
         | might be much easier to sync those few tokens in your system
         | into some local cache and let them expire automatically
         | (because you know when they expire as it is contained in the
         | token).
         | 
         | But yes if all of this sounds complicated, use sessions and a
         | distributed redis for your session or just the database.
        
         | mooreds wrote:
         | Exactly this! If you are hitting an authorization server via
         | the introspect endpoint, why not simplify things even further
         | and just hit dynamodb or redis or database and check the value
         | of a cookie?
         | 
         | A few reasons why you might want the opaque token come to mind:
         | 
         | * You want the OAuth ecosystem (the libraries, the scopes, the
         | user permissioning)
         | 
         | * You are being forced to use an opaque token because your user
         | authenticates somewhere else, and they only provide you an
         | opaque token.
        
           | ffo wrote:
           | Or you want to share sessions across multiple domains.
           | 
           | This is where a identity service also can help ;-)
        
         | ffo wrote:
         | Well you want to check your session cookies as well against
         | something ;-)
         | 
         | Surely you could trust a signature and lifetime but that makes
         | the cookie no different than a JWT (only storage wise the
         | differ in that case).
         | 
         | Generally speaking it is recommended to use opaque tokens and
         | rely on the userinfo / introspect endpoint call to make for the
         | session management.
         | 
         | Only in specific cases where latency and/or scaling might
         | become an issue you should opt for JWT. At least this is my
         | opinion.
        
           | ketzu wrote:
           | > Well you want to check your session cookies as well against
           | something ;-)
           | 
           | I think that is the point of the op: If you have to check a
           | db to realize revocation, then you can use session cookies
           | because they also need to hit the db. (Because you don't get
           | rid of the db hit for using jwt).
        
             | marcosdumay wrote:
             | Well, that certainly depends. One accesses the db on every
             | request, the other accesses the db on every correct request
             | (and the db is smaller).
             | 
             | As a rule, there is no difference. But if you are one of
             | the exceptions, those can have differences of orders of
             | magnitude.
        
         | franky47 wrote:
         | Another drawback for JWTs (when used fully statelessly) is the
         | inability to list active sessions on other devices (which may
         | lead to revocation).
         | 
         | That being said, always going to the database for connecting an
         | opaque session token to an identity can quickly become slow,
         | and if those features listed above are not desirable, having a
         | blocklist of revoked JWT IDs in an in-memory cache (like Redis)
         | can bring back some performance benefits.
        
           | Awerion wrote:
           | You still can add a post response filter to update some
           | statistics table after you send out the response to the
           | customer to keep latency low and pressure on db low too.
           | 
           | Still very few companies need something like this.
        
           | Aeolun wrote:
           | > always going to the database for connecting an opaque
           | session token to an identity can quickly become slow
           | 
           | PHP does this every single request. I've never had enough
           | users that this became a significant issue (and you probably
           | don't either)
        
           | mooreds wrote:
           | > having a blocklist of revoked JWT IDs in an in-memory cache
           | (like Redis) can bring back some performance benefits.
           | 
           | Doing this obviates some of the benefits of JWT's
           | statelessness, but for situations where revocation is really
           | important and you can't have that few seconds of JWT validity
           | after a user logs out, this totally works.
           | 
           | My employer has an article about this topic here:
           | https://fusionauth.io/learn/expert-advice/tokens/revoking-
           | jw...
        
           | nodefortytwo wrote:
           | Not all requests are created equally, maybe you don't check
           | jwt revocation on some high throughput read endpoints but on
           | updates or reading of sensitive data you do check that list.
           | 
           | with JWTs you have the flexibility with the opaque you don't.
           | 
           | JWTs also allow you to do client-side logic on things like
           | entitlements but then verify against database when the user
           | tries to view something
        
           | philliphaydon wrote:
           | > always going to the database for connecting an opaque
           | session token to an identity can quickly become slow
           | 
           | If select by id or token is slow for you then I worry about
           | the rest of the application quality. Probably much slower
           | elsewhere that the identity lookup is the least of your
           | concern.
        
       | Octoth0rpe wrote:
       | Lots of messy terminology use here. Example:
       | 
       | > In addition, since [opaque] tokens are stored on the server,
       | they can carry more data than JWTs, and you can easily revoke
       | them if necessary.
       | 
       | Opaque tokens don't carry _anything_. THey're just an identifier
       | used to query a database inside your application. The article
       | repeatedly implies there is meaningful content inside an opaque
       | token.
       | 
       | More messiness:
       | 
       | > Opaque tokens cannot be read by people that hold them since
       | they are undecodable strings. A client cannot read the contents
       | of the token
       | 
       | Sure they can be read. It's just that the totality of the content
       | _is_ the token itself.
        
         | dfee wrote:
         | > Opaque tokens don't carry _anything_.
         | 
         | Opaque tokens are opaque to consumers. There's no limit on what
         | can be in there, as long as they're opaque. So yeah, you don't
         | need that token to just be a PK. It can be a real payload
         | (generally encoded).
        
           | Octoth0rpe wrote:
           | > Opaque tokens are opaque to consumers.
           | 
           | > It can be a real payload (generally encoded).
           | 
           | Based on your definitions, a JWT is therefore a specific kind
           | of opaque token. I don't think it is personally.
           | 
           | I think we really should be talking about tokens as falling
           | into two categories, of which JWT is an implementation of the
           | first:
           | 
           | 1) stateless - the token contains meaningful content that can
           | be verified by a consumer. JWT is such an implementation with
           | a standardized way of verifying the content without
           | additional database queries (excepting revocation here)
           | 
           | 2) pure identifiers - the token is merely an identifier, and
           | all consumers must reach out to some other service (eg redis)
           | to retrieve the details/capabilities that the session should
           | have.
           | 
           | Edit: alternative proposed terms: content-full, content-less
        
             | jimbobimbo wrote:
             | Opaque token is called opaque for a reason - only the
             | issuer knows what's in it, whether it has content or not,
             | is it an identifier or an encrypted payload, what to do to
             | make use of it.
             | 
             | Content-full and content-less break that abstraction.
        
               | marcosdumay wrote:
               | This is a hard area to work on, everybody that says
               | something apply their own meanings to the words, you can
               | never know what anybody else says.
               | 
               | Anyway, I have always understood it as the token being
               | opaque for the verifier too, that only ever tested it for
               | equality. The token that is opaque only for the holder is
               | normally called "encrypted". It may not be opaque to the
               | issuer, but that doesn't change much.
               | 
               | But anyway, depending on what you read, you will get
               | different meanings.
        
               | P5fRxh5kUvp2th wrote:
               | > Anyway, I have always understood it as the token being
               | opaque for the verifier too
               | 
               | Which falls flat on its face the second you realize the
               | "verifier" can pull out information based upon that
               | opaque token.
               | 
               | It just means the intent is not for the person receiving
               | it to do anything except reflect it back on subsequent
               | requests. That's it. Typically it's done by handing
               | something that is meaningless without context, said
               | context not being available to the consumer being issued
               | the token. But there is absolutely nothing that says you
               | can't hand them a JWT meant to be used as an opaque
               | token. If you're really worried about it, encrypt that
               | bad boy before giving it to them.
        
       | senko wrote:
       | My biggest problem with JWT is that it's way overhyped, leading
       | less experienced devs to believe JWT is the only way to implement
       | auth, unless you use a 3rd party provider.
       | 
       | JWT is a solution to a problem 95% of us don't have:
       | https://apibakery.com/blog/tech/no-jwt/
        
         | hbrn wrote:
         | To add to that, even if you have microservices everywhere on
         | the backend, JWT is still rarely a good choice. Those services
         | are typically exposed to customers via some sort of API
         | Gateway/BFF. So if your clients don't speak to microservices
         | directly, authentication between those services could easily be
         | done via plain old HTTP Basic Auth.
         | 
         | Stripe has been doing that for their public API since forever,
         | and that's one of the big reasons why it is so easy to work
         | with them.
        
           | tobyjsullivan wrote:
           | It's worth noting this coconut pattern (hard auth facade,
           | soft interior), while popular and helpful for dev efficiency,
           | is a weak security practice. Using simple pre-shared keys
           | between internal services excludes any meaningful access
           | controls over user data. Whether that's important depends on
           | the domain.
           | 
           | For stripe, though, I'm surprised they wouldn't want to
           | ensure internal data requests are being made on behalf of
           | customers who should actually have access to the data.
           | 
           | Also, for bigger companies (although, why not smaller ones?),
           | you hit a point where you can't keep blindly trusting every
           | service. Better to have internal security controls.
           | 
           | As for when these tradeoffs are appropriate, hard to say. But
           | a good rule of thumb could be when the product is big enough
           | to need an SOA.
        
             | hbrn wrote:
             | > As for when these tradeoffs are appropriate, hard to say
             | 
             | And that is my biggest problem. If you don't know whether
             | you need something, you don't need it.
             | 
             | Or you just don't have enough expertise to understand why
             | you need it, but that means you will implement it the wrong
             | way anyway.
        
               | marcosdumay wrote:
               | > If you don't know whether you need something, you don't
               | need it.
               | 
               | That's a bad approach for security.
               | 
               | Starting with the solution is the wrong way to do it, but
               | you certainly need to actively look if you have problems.
        
               | hbrn wrote:
               | Let's say you're a startup that's hiring it's 5th
               | engineer.
               | 
               | Should you do criminal background checks? Install spyware
               | on laptops? Forbid hiring from other countries? Restrict
               | developer access to production env? Invest all your
               | development time into security features until you run out
               | of those?
               | 
               | If you actively look for problems, you will justify all
               | of those.
               | 
               | Security is not about knowing which problems exist and
               | fixing them all. It's about knowing which risks are
               | acceptable at your current stage. If you don't know which
               | risks are acceptable, applying random security practices
               | is worse than no security at all. At least when there's
               | no security you are aware of it.
               | 
               | If you can't come up with an attack vector where HTTP
               | Basic Auth causes significant problems, you don't need
               | JWT to secure communication. And even if you can come up
               | with an attack vector, is it really easiest one to
               | execute?
               | 
               | Speaking of attack vectors, how many of the folks that
               | use JWT for inter-service communication actually rotate
               | encryption keys when anyone who has access to them leaves
               | the company? My bet is very few.
        
               | P5fRxh5kUvp2th wrote:
               | Why do security people think security trumps everything?
               | 
               | It's a serious question. As time goes on I more and more
               | land on the side of Linus Torvalds wrt to security.
               | 
               | It kills me the amount of stupid shit I've seen done in
               | the name of security.
               | 
               | If security people were to come up with driving
               | standards, no one would be allowed to turn left because
               | it's more dangerous then turning right.
        
             | schwap wrote:
             | Ironically, authorization downstream of an API gateway is
             | an application that JWTs are a good candidate for.
        
           | dwaite wrote:
           | You have different approaches of security depending on your
           | desire for risk mitigation. Examples (with somewhat made-up
           | names);
           | 
           | 1. An ingress moat - your ingress makes decisions on whether
           | someone should be allowed in, after which internally anything
           | goes.
           | 
           | 2. Two-stage auth - building on top of the above, internal
           | messages need authentication/authorization for communication
           | channels to be established. This might be basic, x509,
           | kerberos, or federation-based protocols. Microservices
           | environments might use SPIFFE for this.
           | 
           | 3. Messenger auth - in addition to the above, requests need
           | to show evidence of direct/indirect interaction with the
           | parties involved. For example, an access JWT may be sent
           | around since it would provide indication of a user and
           | tenant.
           | 
           | 4. Intermediary-authorization - a variation of the above,
           | evidence is required on each communication channel 'hop' that
           | the initiator(s) are authorized to make the request against a
           | service. This may involve more centralized services to create
           | many opaque/integrity-protected authorization decisions from
           | an external systems view.
           | 
           | 5. Transactional auth - another variation of 3, evidence is
           | required specifically that a given action is authorized,
           | including parties and potentially parameters. This might be
           | sent directly from the original initiating party, or may be
           | created for internal systems close to the ingress point.
           | 
           | Note that for a service with a public API, all of these can
           | hypothetically look identical. However, once you get to a
           | certain amount of internal authorization checks, you
           | naturally start to try to represent those with integrity-
           | protected stateless tokens to avoid needing a massive
           | centralized system with low latency consistency and high
           | uptime needs. OAuth access and refresh tokens were designed
           | to help there.
        
         | feoren wrote:
         | > This brings us back to how we implement authentication in
         | Node projects you generate with API Bakery. If you've read all
         | of the above, no surprise here - we use bearer tokens.
         | 
         | WTF? They just spent the whole article talking about how bearer
         | tokens were stupid (everything they said about JWT applies to
         | all bearer tokens). And then they say "instead of this thing we
         | said was stupid, we use the exact same thing but named
         | differently". WTF?
        
           | jsmith45 wrote:
           | Nonsense. Issues like inability to revoke JWTs don't apply to
           | bearer tokens where the API server needs to query the token
           | issuer to found out who the user is (which can then implment
           | revoking the token simply by dropping the record for the
           | token from the DB, all further calls will fail the lookup!)
           | 
           | Remember they stated:
           | 
           | > Major advantage of JWT compared to bearer tokens [...] is
           | that they don't require looking up the token.
           | 
           | Other problems with JWTs vs opaque bearer tokens they listed
           | include:
           | 
           | - increased attack surface due to complexity of JSON
           | parsing/validation
           | 
           | - misconfiguring JWT libraries to allow no signature
           | 
           | - leaking data to users because you thought JWTs were
           | encrypted
           | 
           | Now you are right that some of the complexities involved with
           | JWTs like refresh token can apply with arbitrary bearer
           | tokens, especially if you want to limit the lifespan of the
           | access token, but those are implementation choices.
           | Technically you can just have a single long lived bearer
           | token instead of a long lived refresh token, and a short
           | lived access token.
        
         | yencabulator wrote:
         | Worse than that, even when JWT is a solution to a problem you
         | have, it's a bad solution.
         | 
         | https://web.archive.org/web/20180324054020/https://storify.c...
         | 
         | https://twitter.com/FiloSottile/status/1300946068411121665
         | 
         | https://insomniasec.com/blog/auth0-jwt-validation-bypass
         | 
         | https://paragonie.com/blog/2017/03/jwt-json-web-tokens-is-ba...
        
         | goodpoint wrote:
         | Like most web stuff and the blockchain, JWT sound fancy but it
         | is a very trivial thing.
        
           | [deleted]
        
       | Aeolun wrote:
       | I feel people come down too hard on JWT. If you do just two
       | things there's basically no difference between sessions and
       | tokens.                 Don't use it for storing sensitive data
       | Expire often
        
         | dkarl wrote:
         | Where I've seen this turn into an argument is when people
         | disagree about whether authorization info is "sensitive." Is it
         | okay to send a list of roles or other authorization info in an
         | unencrypted JWT? Security-wise this seems like it adds risk,
         | but people often argue that it's a good trade-off in order to
         | avoid a round-trip to an auth server (probably with a caching
         | layer in front) for every call.
        
           | gboone wrote:
           | I figure unencrypted should be useful to the frontend, but
           | use encrypted for authentication or authorization.
           | 
           | Unencrypted: maybe a user preference, or first name, or
           | something that adds value but does not overlap with auth.
           | Like if a frontend could serve the same functionality across
           | three departments but the styling is different, the token's
           | unencrypted claims could determine which style set to use.
           | 
           | Encrypted: user uuid, roles, maybe other known settings,
           | things the backend can handle. Someone stealing a token will
           | just try it anyway whether they can see claim or not, but
           | because it's encrypted it will get decrypted so it's also a
           | different logic flow than unencrypted and could trigger a
           | process i.e. did it come from an accepted ip address or
           | range? Does the ip match the previous? Does the ip match the
           | other known ip for a websocket? So also in this sense we
           | wouldn't want anyone to know what else we might check.
        
             | [deleted]
        
             | dkarl wrote:
             | The front end almost always needs to know what a user is
             | authorized to do, because it is reflected in the UI. Which
             | edit/delete buttons are visible and active? Is there a link
             | to the admin page? Is there a link to a supervisor
             | dashboard? Most apps send that information to the front end
             | in a way that maps 1-to-1 to how they model authorization
             | on the back end, often using exactly the same language, in
             | which case you don't gain much by encrypting it in the JWT.
             | But if you are taking measures not to leak your
             | authorization model in the front end, then it makes sense
             | not to expose it in an unencrypted JWT.
        
           | ehutch79 wrote:
           | And then most people hit the db anyways, since they use the
           | jwt as a session cookie anyways.
        
         | jrochkind1 wrote:
         | If there is no difference, then what is the advantage of JWT?
        
           | hobofan wrote:
           | That they've been around for long enough for proper
           | implementations in all major languages to exist, their
           | pitfalls being documented and a lot of devs have some
           | familiarity with it.
           | 
           | With that they are a better choice than most
           | homebrew/framework-specific solutions.
           | 
           | There are some other established (/"standardized") solutions,
           | which might fit your use-case better though, but most of them
           | lag behind JWT in implementations/dev familiarity.
        
             | goodpoint wrote:
             | Spot on. Even better if they used a better serialization
             | protocol than stupid JSON.
        
               | Sohcahtoa82 wrote:
               | What's wrong with JSON?
        
               | fireflash38 wrote:
               | JSON really is the worst serialization, except for all
               | the others.
        
       | mvf4z7 wrote:
       | My biggest problem with using JWTs for authenticating a SPA is
       | where do you store them so that a user does not have to login
       | every time they visit your application? Every SPA tutorial I have
       | seen says to throw them in the browser's localStorage. Well now
       | you just opened yourself up to XSS vulnerabilities. Any code
       | running on your page can access localStorage and make requests to
       | ship the tokens anywhere they would like.
       | 
       | I prefer session cookies for web applications. Sure you have to
       | worry about CSRF, but that is easily solved with CSRF tokens.
       | Furthermore, is CSRF even really an issue when you are using a
       | JSON API and have CORS properly configured.
        
         | debacle wrote:
         | Adding a CSRF middleware to your app is something that you need
         | to do once, ever.
        
         | mooreds wrote:
         | > where do you store them so that a user does not have to login
         | every time they visit your application?
         | 
         | We recommend HTTPOnly, secure cookies for storage with an SPA.
         | Diagrams here: https://fusionauth.io/learn/expert-
         | advice/authentication/spa...
         | 
         | If you need to access APIs from elsewhere, run an API proxy
         | server side that can validate the JWT and then forward on the
         | requests.
        
       | xvinci wrote:
       | Unless I misread I consider this statement not true or
       | contradictory:                 it has all the information the
       | server needs except the signing keys, so the server doesn't need
       | to store this information server-side. This means that users can
       | get a token from your authorization server and use it in another
       | without those servers needing to consult a central service.
       | 
       | In order to not have to care about rotating keys, a typical
       | Resource Server would fetch the public key from the SSO server.
       | Not necessarily in real-time, but at least on a frequent periodic
       | basis. It even says "except the signing key", which is half true,
       | since the public key needs to be well.. public and available.
       | 
       | Now this may be nitpicking but it comes with an important
       | implication: Your jwt validating party needs to have network
       | access to the SSO service (unless you want to provide keys for
       | token verification yourself, which I do not recommend), which is
       | not always a given, especially in hybrid setups (On-Prem +
       | Cloud).
        
         | mooreds wrote:
         | > In order to not have to care about rotating keys, a typical
         | Resource Server would fetch the public key from the
         | [authorization] server.
         | 
         | Another option would to be prepackage N public keys with the
         | resource server during deployment. This means there is
         | absolutely no network access required, just filesystem access
         | to the public keys.
         | 
         | You want more than 1 so that you can rotate the signing keys if
         | you need to, without redeploying said service.
         | 
         | What is the correct value for N? I dunno, depends, but it's not
         | hard to generate 100 public/private keypairs and then bundle up
         | the 100 public keys into a deployment artifact.
         | 
         | Is this as common as using JWKS? No, not in my experience. Is
         | it possible? Absolutely.
        
         | gboone wrote:
         | Maybe it's about "can get" vs "should be allowed to get"? They
         | can carry whatever so it's technically true, right?
        
           | xvinci wrote:
           | It was more about the                 and use it in another
           | without those servers needing to consult a central service.
           | 
           | part. Unless you take care of key distribution yourself (like
           | another poster wrote), this consultation of a central service
           | has to take place to exchange key information (but not for
           | additional authentication or authorization information).
        
         | ffo wrote:
         | Well true, public keys would be better wording wise.
         | 
         | One thing I just wanted to append to this here:
         | 
         | > Not necessarily in real-time, but at least on a frequent
         | periodic basis.
         | 
         | Periodically fetching the keys is not really a best practice on
         | its own. The consumer (RP) must be able to handle newly
         | published keys at runtime. Since a JWT includes a KID it is
         | recommended to lookup a local cache pre-filled from a scheduler
         | while fetching new KIDs on demand.
        
         | magicalhippo wrote:
         | Indeed. We validate Azure AD tokens for our native application.
         | Not all of our on-prem installations have unrestricted internet
         | access. So we have a task that periodically checks and
         | downloads Azure's signing keys[1], so we can distribute them to
         | our customers.
         | 
         | [1]: https://login.microsoftonline.com/common/v2.0/.well-
         | known/op... (jwks_uri element)
        
       | brokenwren wrote:
       | As this applies to access tokens, if your application doesn't
       | need a JWT, it shouldn't care whether the authorization server
       | returns a JWT or an opaque token. On the flip side, if your app
       | needs a JWT, then the authorization server must return one.
       | 
       | Revocation is either offered by the authorization server or
       | managed by the app. If the authorization server manages it, then
       | JWTs vs. opaque tokens are not a concern because the
       | authorization server issues and revokes its own tokens. If the
       | app manages it, then generally it does so based on the token
       | type. If the app revokes based on opaque tokens, it can handle
       | any type of token, including JWTs. If it revokes based on JWTs,
       | then JWTs are required.
       | 
       | Beyond that, the only differences between the two token types are
       | size and data leaks. Size rarely matters (hehe), so just ignore
       | that. Data leaks are only an issue if you app is leaking JWTs,
       | which is usually considered a critical vulnerability. Remember
       | that access tokens are the main units of identity and if I steal
       | an access token, I effectively become that user/client.
        
       | b0afc375b5 wrote:
       | Whenever I see jwt I always think of tptacek's arguments
       | 
       | https://hn.algolia.com/?dateRange=all&page=0&prefix=false&qu...
        
         | 42e6e8c8-f7b8-4 wrote:
         | Thanks for the link. tpacek makes useful arguements.
         | 
         | I've come to like JWT's for mundane, tiny projects because I
         | can use https://www.keycloak.org/ and get a lot of boilerplate
         | account stuff for free -- password reset, registration page,
         | eula gate, et c.
        
           | ffo wrote:
           | Well you can have the turnkey of keycloak and JWT optional
           | with ZITADEL ;-)
        
       | aaaa_vougoza wrote:
       | I came here to see what in the hell James Webb Telescope is not
       | dealing with some opaque stuff on the universe and I got decepted
        
       | orange_joe wrote:
       | I don't have experience with JWTs, but if you can encode data,
       | why couldn't you encode a "freshness" time stamp and just
       | invalidate the token after an elapsed time. Does this compromise
       | the encryption?
        
         | sibit wrote:
         | You can. Usually it's an "exp" value that you set when the
         | token is issued. The time can be whatever you want, I might do
         | something like now + 15 minutes. Then when verifying the token
         | you can check if exp <= now kick out a 401 response.
        
         | mattacular wrote:
         | You can do that. A related problem: there is no obvious way to
         | revoke early (ie. before the timestamp that was encoded when
         | the token was issued). There are solutions but they require
         | building extra mechanisms.
        
       | FreakLegion wrote:
       | Something that never comes up in these discussions is services
       | with built-in JWT validation, like AWS API Gateway HTTP APIs. If
       | you're already using one of these, you might as well take
       | advantage of JWTs _in addition to_ your scheme of choice, whether
       | that 's opaque tokens or something else. Let the service provider
       | worry about unauthenticated people banging on your APIs.
       | 
       | You can even maintain statelessness with opaque tokens if you
       | really need it, e.g. issue both a JWT and a session cookie bound
       | together by some shared value, say Fernet tokens. One goes in the
       | JWT in local storage (anti-CSRF), the other goes in an HttpOnly
       | cookie (anti-XSS), requests still require both to decrypt to the
       | same value after the service passes them through.
       | 
       | Generally this is overkill, though. JWTs for the service and your
       | preference for the app works fine decoupled.
        
       | phamilton wrote:
       | We moved from jwt to opaque tokens and it's been fantastic. We
       | also moved from using redis as our token store to using postgres
       | (aurora).
       | 
       | Querying against over 100M on postgres adds one or two
       | millisecond p99 latency to all requests. That's perfectly fine.
       | In fact, that's about the same performance we saw with Redis.
       | Both were over the network, so I presume the network accounts for
       | most of that delay.
       | 
       | Having them in an rdbms is so convenient. It makes customer
       | facing feature like enumerating current sessions very simple. It
       | makes token expiration and remote logout simple. It makes
       | spotting weird bugs much easier.
       | 
       | I can't recommend it enough.
        
       | rawoke083600 wrote:
       | Whats the drawback for just including the ip in jwt and revoke if
       | either time is up or ip change ?
        
         | nkristoffersen wrote:
         | I would imagine it would be a very poor user experience.
         | Especially on mobile, where you jump around 4G/5G/WiFi networks
         | and get a new IP address each time.
        
           | deepstack wrote:
           | or if the user allows JS in their browser, then just do some
           | GPU/CSS/Font Collections,etc. finger printing and get the
           | unique id, since all the major bowser vendors are not fixing
           | this problem (except may be for webkit).
        
         | lakomen wrote:
         | The IP can change, is not guaranteed unique (many people can be
         | behind 1 IP). Imagine unstable mobile connections going over
         | 4/5g or random wifi as you move.
        
         | Awerion wrote:
         | Best things would be webauthn were you have crypto hardware
         | like your smartphone
        
         | xxs wrote:
         | you can have multiple IPs at the same time.
         | 
         | The "IP changes" is a common fallacy - even the mobile IP
         | depend on the datacenter(s) process it. There is no grantee
         | there will be a designated aliasing, and effectively there
         | could be multiple IPs for the same client interleaving.
        
         | notimetorelax wrote:
         | IP can change multiple times when switching between mobile
         | stations and wifi hotspots. Plus IP may change for each new TCP
         | request if your operator uses CGNAT
        
       ___________________________________________________________________
       (page generated 2022-09-29 23:02 UTC)