9 ms·
JWT vs. Opaque Tokens
- pmontra 4y agoI 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.
- franky47 4y agoAnother 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 4y agoYou 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 4y ago> 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 4y ago> 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-jwts https://fusionauth.io/learn/expert-advice/tokens/revoking-jw...
- nodefortytwo 4y agoNot 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 4y ago> 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.
- Awerion 4y agoThan 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.
- ffo 4y agoWell 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 4y ago> 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 4y agoWell, 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.
- mooreds 4y agoExactly 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 4y agoOr you want to share sessions across multiple domains. This is where a identity service also can help ;-)
- rawoke083600 4y agoWhats the drawback for just including the ip in jwt and revoke if either time is up or ip change ?
- nkristoffersen 4y agoI 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 4y agoor 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 4y agoThe 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 4y agoBest things would be webauthn were you have crypto hardware like your smartphone
- notimetorelax 4y agoIP 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
- xxs 4y agoyou 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.
- tialaramex 4y agoAn 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.
- aaronmu 4y agoWhat'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.
- ffo 4y agoThe 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.
- cnorthwood 4y agoThere isn't one - the session identifier is an example of an opaque token
- senko 4y agoCookie 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.
- mooreds 4y agoFor 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-origin_policy https://developer.mozilla.org/en-US/docs/Web/Security/Same-o...).
- senko 4y agoMy 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/ https://apibakery.com/blog/tech/no-jwt/
- candiodari 4y agoYes, but what developers want from JWT is: 1) not having to worry about authentication in their app (and not about security issues, exploits, account recovery, fake accounts, bots, ...) 3) the ability to use it in any framework they want (e.g. the Go standard library "framework") 4) the ability to "upgrade" to full microservice authorization And yes, these are sort-of kind-of not-quite-but-almost provided in Django, Spring and Ruby On Rails, but if you want to use whatever framework you want ... JWT is definitely the closest thing available, or at least it seems so.
- goodpoint 4y agoLike most web stuff and the blockchain, JWT sound fancy but it is a very trivial thing.
- deleted 4y ago[deleted]
- hbrn 4y agoTo 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 4y agoIt'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.
- mooreds 4y agoFull 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 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.
- wokwokwok 4y ago> …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.
- Aeolun 4y agoI 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 4y agoWhere 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.
- ehutch79 4y agoAnd then most people hit the db anyways, since they use the jwt as a session cookie anyways.
- gboone 4y agoI 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 4y ago[deleted]
- 4y ago
- b0afc375b5 4y agoWhenever I see jwt I always think of tptacek's arguments https://hn.algolia.com/?dateRange=all&page=0&prefix=false&query=author%3Atptacek%20jwt&sort=byPopularity&type=comment https://hn.algolia.com/?dateRange=all&page=0&prefix=false&qu...
- 42e6e8c8-f7b8-4 4y agoThanks 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/ https://www.keycloak.org/ and get a lot of boilerplate account stuff for free -- password reset, registration page, eula gate, et c.
- ffo 4y agoWell you can have the turnkey of keycloak and JWT optional with ZITADEL ;-)
- kyrra 4y agoIt'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.)
- xvinci 4y agoUnless 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).
- gboone 4y agoMaybe it's about "can get" vs "should be allowed to get"? They can carry whatever so it's technically true, right?
- xvinci 4y agoIt 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 4y agoWell 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 4y ago
- orange_joe 4y agoI 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 4y agoYou 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 4y agoYou 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.
- mvf4z7 4y agoMy 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 4y agoAdding a CSRF middleware to your app is something that you need to do once, ever.
- mooreds 4y ago> 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/oauth-authorization-code-grant-jwts-refresh-tokens-cookies 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.
- rubyist5eva 4y agoDon'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.
- Xeoncross 4y agoSession 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.
- brokenwren 4y agoAs 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.
- aaaa_vougoza 4y agoI 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
- FreakLegion 4y agoSomething 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 4y agoWe 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.
- Octoth0rpe 4y agoLots 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 4y ago> 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 4y ago> 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 4y agoOpaque 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.