> 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:
- 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?
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?
"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.
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/...