Hacker News new | past | comments | ask | show | jobs | submit login

This skips over one other big way that I’ve always seen JWT implementations fall over - sign out/session invalidation.

A JWT has all the information for verifying its own lifetime contained within it, which is cool in that you don’t need to hit the DB to verify it… until you want to invalidate it before the embedded expiration is hit.

Then you need to hit the database or some cache layer to verify that it isn’t invalidated, and now one of the biggest reasons to use it is gone.

They do mention that for CRUD operations you’ll need to hit the DB anyways, which is in the same vein as this issue tho.




Not really true if you use an access/refresh token system. The access token doesn't hit the DB for auth, the refresh token does. You have an access token with a lifetime of say somewhere between 1-10 minutes. If you want to invalidate a session, you just revoke the refresh token and any access tokens will be invalid soon after. In a system where a user is making 10+ requests in a minute, that can be well worth it to reduce stress on the DB without an appreciable loss in security.


Cookie sessions are usually stored in fast caches like redis so the performance hit is negligible. Most people will never reach the performance ceiling of a beefy single redis instance so why bother complicating the system?


Even when storing the cookies in a database like Postgres, they are fast enough because it's obviously indexed, and it's probably cached in many usage patterns. JWT is solving a non-problem for most people. Now, if you're talking machines talking to machines, all owned/operated by the same entity, go wild with JWT's if you want.


> Even when storing the cookies in a database like Postgres, they are fast enough because it's obviously indexed, and it's probably cached in many usage patterns.

If you scale up high enough, it does matter.

But beyond that, it is also about decoupling the server serving the content and the user database.

To give you an example, using a traditional session cookie model, whenever my server gets a request, it has to look up the associated session info, and then possibly join multiple tables to see if a specific user for that specific session is authorized to access that content.

There are going to be many joins involved. Even with good caching, it will still be a more complex operation.

Even if not computationally complex, it will be logically complex.

But when using a JWT, my server actually does not need ANY db access. It merely needs to verify the cryptographic validity of the included JWT header, which uses no IO. After that, it can safely trust any user metadata included in the JWT.

So, if a user has paid for access to all premium content after 2018, you would just include a field for that in your JWT payload. Done.

It depends of course on how your business data models work of course. But you can often put enough information in your JWT to cut out a lot of account processing logic.

> JWT is solving a non-problem for most people.

I think people are cargo culting JWTs.


> But when using a JWT, my server actually does not need ANY db access.

You don't need any db access with signed cookies either. Just stash your data in a signed cookie and you're done. Should you need more than 4k for session data, maybe it's time to rethink about what should be stored in the session and what should be stored in the db.


I know a good spec for signing json data to store it as a token here, too


When people talk about caching user information, access is one of the things cached. That complicated joining happens exactly as often with sessions as it does with JWT's.


No, with JWT parsing it doesn't even have to look anything up, cached or otherwise. The JWT itself contains the information directly.

I could have a server that doesn't have any access to the database at all, and it could still render content for the user.

And if the server is for something critical, like purchases, it can still use redis on each request to verify that a JWT is still valid.


I was responding to this:

> To give you an example, using a traditional session cookie model, whenever my server gets a request, it has to look up the associated session info, and then possibly join multiple tables

It does this on initial logon and then stores it in cache. You can think of a JWT as cache as well.

The point is, it only happens once for both.


Still not comparable. Session cookie requires a session datastore server side. It then requires to enable sticky session, to replicate the session between the server or to have a distributed datastore. if user information are cached it will require either a local cache or a distributed cache.

JWT token does not require that.

Both solutions requires invalidation.


I'm unsure why you're so hell-bent on arguing something so silly, but at the end of the day you made a mistaken point and I responded to it.

You want to try and move the goalpost that's on you, but your point about the joins is flawed. As is the rest of it, but I'm certainly not going to waste my time.


you can use signed cookies for sessions - which have none of the drawbacks you mentioned. i.e. session data and expiration form the payload, and you sign the payload - then you validate the expiration and signature on subsequent requests.


Assuming you mean express' cookie parser signed cookies? Or maybe rails?

Solves some of the session problems..

Benefits:

Cookies - when set to http only + secure only are safer?

Drawbacks:

They're not cross-compatible No expiration baked in No not-before baked in Limited to hmac validation (no public key crypto options that I know of)

Unless you mean using a JWT as a cookie value. I guess that could work?


no - i mean the generic concept of a signed cookie as I described, which would have none of the drawbacks you mentioned. They can even be encrypted, if desired.

There are many, many implementations in use "in the wild". They are just signed payloads, so they can contain "expiration", "not-before" or whatever else you think isnt "baked-in". You can use any method of signing them, but would probably make sense to use a strategy that is considered secure :) No doubt the libs you mention can be extended trivially with this "missing" functionality.

Signed/encrypted cookies predate JWT - they even predate JSON...

Im not presuming that they are better/worse than JWT, just responding to the incorrect statement about cookie based sessions requiring server-side storage


How does this solve it? You still need to wait 1 minute.


What security context are we talking about where that 1 minute matters?


A person has accessed your account and you’ve noticed it via sign-in-email. You change your password.

Attacker now still has 1-10 minutes to access your account.


I have this rant about people creating problems for themselves.

A perfect example is when SPA's were created, but it broke browser history. So we get a new standard with the ability to edit browser history.

I feel like refresh/access tokens fall into the same vein. If you need that don't use JWT's. The choice of JWT is the problem here, refresh/access tokens are a workaround.


> sign out/session invalidation

I wrote it up in another comment, but basically: if you're using JWTs, and you have lots of services calling each other in a request (as you might with microservices), it's entirely appropriate to have a session check ("remote introspection") when you access sensitive information, such as PII.

And, maybe, at the edge layer as well.


I feel like this point gets overblown. Subscribing to an "invalidations" message queue seems pretty straightforward. What am I missing?


Yeah that’s what we ended up doing but do hate that everyone who encounters this problem has to cook up their own solution for a scenario that’s very common.

It’s not terribly difficult to do because most JWTs should only last 10 to 15 minutes. We just broadcast the “jti” of the blocked JWT along with its expiration. The recipients just hold it in memory for that duration. That’s a relatively compact message so it’s quite simple to hold for 10 to 15 minutes.

One of you mentioned that it fails open. True but it’s mitigated by the fact that it’s only alive for 10 to 15 minutes (which you can still do a lot of damage with depending on scenario) and we repeat the message over a few times. In our case, it’s just being extra cautious since we’ve never seen our message bus fail. And if it does, functionality is impaired anyways for many of our services so it also inconveniences the attacker too. Maybe your scenario is different but in our case, it’s more than good enough. The attacker has to line up multiple holes to even get to this point. Or put differently, if an attacker is going to succeed in penetrating, it won’t be because we failed to receive a log out message from our message bus after someone has already logged out but before the JWT expired.


Can you explain what this looks like? So each application that authenticates its requests using the jwt subscribes to a message queue and replicates the data in some database local to it? Then it checks that database each time a new request comes in?


Pretty much, with the type of local db/cache changing based on the amount of concurrent invalidation you expect.

The theory is that your list of prematurely invalidated tokens (expired by user before the token's own expiry date) is much, much lower than your active tokens, so you only have to check a requests JWT against this tiny subset, rather than every active session to confirm it doesn't exist.

It has its own unique failure modes where an invalidation doesn't make it to all listeners, so either you can expend effort to make it more robust (and it's again, less data to sync than the sum of all active sessions) or just live with some parts of the system allowing the token for a few minutes..I

Typically, unless you are at a very large scale, or dealing with offline clients, I'd stick to traditional cookies + session.


That makes sense. Thank you.

Honest question - What would you do to justify doing this over using cookie based sessions? Like, are there back of the napkin calculations you could do to find when one approach becomes comparable in performance to another? That's one thing in system design that I struggle with.


Depends on how many invalidations you see. Some systems can get away with a message queue with an in memory copy of whatever's still in TTL with a bloom filter in front to make for a really cheap check. If you have more invalidations than a simple library implementation can handle, you do a similar thing with a DB like Redis sitting off to the side.


An invalidations queue will fail open if the queue does not deliver. If you check a session token against a database and the database is down, you fail closed.

There are systems at scales where you have to take that hit, but the overwhelming majority of people don't run them.


How many do you retain?


Not that many since they only last 10 to 15 minutes so you can just set the TTL to that. Also, you only need to retain the “jti” of the token and not the entire token. So you can hold quite a lot of these jti of tokens even in memory which is what we do. And then after 15 minutes they are ejected from memory.


Why not just have a lower TTL on your JWT?


Then what's the point? Just use sessions at that point.




Consider applying for YC's Fall 2025 batch! Applications are open till Aug 4

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: