Why JWTs Suck as Session Tokens (2017)
developer.okta.com
developer.okta.com
In this media rich age, the data size argument is a bit silly.
The "you're going to hit the database anyway" argument whilst probably accurate in most cases, doesn't invalidate that JWT allows for one or more fewer database hits on every request.
Having built-in integrity checking is definitely a feature. Just because you can do it without JWT doesn't mean that it's not useful that JWT does it.
IMHO the biggest argument against the use of JWT is that you can't easily invalidate JWT sessions. Should you need to dump a users session or if the information contained in that session token has become invalid then you might be in trouble. For my use cases so far however this hasn't been a problem.
JWT is a fine solution for quite a lot of use cases. As with everything tech, just be aware of the limitations and choose wisely.
But JWTs have value for API tokens as they can embed an expiration date for the caller in a known format. But the idea of stateless JWTs with a bunch of valid data for use on successive calls by the server is a bit much. You should contact your auth store of record per invocation for various reasons.
Like you said, be aware of the issues with chosen sig algorithms and be exact on what you choose and just leverage JWT as the format, not blindly following the generation libraries without investigation.
Two weeks ago, I stood in front of a room full of senior developers and architects and asked them "How will we avoid making a leading 'Does the user have permissions?' call or wrapping the request in a try catch in case the user doesn't have access without JWT claims.
They all got mad. Then they conceded that they don't have a solution. Do you have a solution? If not, you can't replace JWTs.
In my CMS, I had support for granular permissions. So you could do this:
if ($user->can('update')) {
if ($postData) {
$this->processUpdate($postData);
}
// display edit form
} elseif ($user->can('read')) {
// read-only
} else {
return error_403_condition();
}
JWT wouldn't have helped much.Also, why can't you make the database request in the request pipeline, right before that "if(hasAccess)" statement. You don't need JWT for this...
You are already wrapping all of your controllers...
Pretty sure most frameworks have a way to structure your code for permission checking.
The auth service/query is higher per-request overhead, but it also keeps things simple. And simple is what you want unless you're dealing with ridiculous scale.
- Database permissions, including row-level security
- Macaroons
- PASETO
- Fernet/secretbox/HMACing a JSON blob
These are different approaches so it's hard to summarize, but they all either give you a property JWT doesn't or avoid a flaw JWT has. You can't seriously believe that nobody did this before 2015.
I wrote PASETO, with a lot of feedback from cryptographers and security engineers, to avoid a lot of the design flaws of JWT.
Learn more about it here: https://paragonie.com/blog/2018/03/paseto-platform-agnostic-...
You can find a lot of implementations available: https://paseto.io
(Also: You almost certainly want to use v2)
Joking on the last two sentences, but that's how you sound when you accuse me of wanting free work. Thanks for the links.
Oh, that's easy to explain. You said:
> This is a real production issue for me, so could you please elaborate on why you think one of these (whichever you prefer) is better or link me to a source?
Specifically:
> This is a real production issue for me,
If you want a cryptographer (i.e. lvh) to solve a real production issue for you, that would in most cases be a business transaction.
If we're being uncharitable, yes.
But the parent didn't ask the other to sit down and write code, or consult, or design a system for them. In the course of an already existing discussion on the merits (and the faults) of various session auth schemes, the parent asked the other person to elaborate on why he said something.
Which people do all the time without getting paid, and the grandparent was already doing (offering his opinion) anyway.
So that it's a "real production issue" for them is irrelevant. I participate in conversations all the time concerning something that is a real business issue for me or the others, and nobody feels like we should be getting paid because we have a talk. In fact half of the discussions on HN concern frameworks, tools, deployment schemes, etc, we use in production, and we have "real production issues" with and are interested in getting other's opinions in the discussion.
I think one can easily see how this is different from a proper consulting gig.
>"If you want a cryptographer (i.e. lvh) to solve a real production issue for you, that would in most cases be a business transaction."
That sounds like what some kind of caricature of a high street lawyer who charges from the first minute, even people they casually talk with. As if answering a comment on HN would equal to doing a consulting gig.
It's doubly uncharitable since the parent asked nicely and also added "or link me to a source". Should he be charged for a link too?
I respectfully disagree.
If it was truly irrelevant, it didn't need to be brought up in the first place.
But it was, and it's what made me believe that the other person was trying to solicit for a security expert to solve a production problem for them without an invoice being involved. It was relevant to my interpretation.
They insist they didn't mean it that way, and I believe them, but it was still relevant.
Whether or not it was relevant in the comment I replied to, it became relevant once it was entered into the discussion.
You can call that "uncharitable" if you want. I don't really have a horse in that race.
It's not like people must have some hidden agenda, or that they necessarily consciously "bring things up" with some ulterior motive.
The parent just shared some context, that he has an issue related to the discussion. If anything, if they really had some hidden motive, like getting market-worthy consulting as part of a HN comment reply (!), they'd have, well, hidden the fact that they have this problem at work.
It's totally common to casually mention that "you know, this issue we're discussing on this thread I also have a work, and why do you say this approach sucks and which do you then suggest".
In fact it happens all the time on HN, between regular developers, the occasional star scientist or programmer (from Alan Kay to Ryan Dahl and Dan Brown), and even far more important and busy pros than some security expert, and I've never heard anybody counting their lost pennies from what they'd have gained if they charged for talking to them...
It's also not like the person the question was addressed to can't handle the matter themselves, and e.g. not answer if they fill they need to be paid for their musings...
The structure of the comment in question is also relevant:
"This is a real production issue for me, so could you [...]"
This reads like a demand if you parse it in spoken English.
If it helps, imagine working in retail and hearing a disgruntled customer ask you to hurry up and give them priority service. Their request might be structured like, "I need to pick my kids up from school at 3, so could you hurry it up?"
Your word choice is far less demanding than theirs. If they wrote their comment the way you just wrote yours, it wouldn't have struck me that way.
The entire reason I brought it up was because I was unsure of the intent. They clarified their intent. I believed them. Life moved on. You're still trying to litigate this.
But none of this matters. What matters is, they didn't intend it that way, and JWT sucks.
> In fact it happens all the time on HN, between regular developers, the occasional star scientist or programmer (from Alan Kay to Ryan Dahl and Dan Brown), and even far more important and busy pros than some security expert, and I've never heard anybody counting their lost pennies from what they'd have gained if they charged for talking to them...
To be fair: me neither. But knowing how humanity is, I wouldn't totally discount that it does happen somewhere on the Internet (maybe even HN).
RLS means your database understands what a user is allowed to see and not allowed to see. It is usually much simpler to express authz in a SQL constraint than it is in code. It's also harder to forget, so you don't get an authz failure in like, one endpoint.
There are numerous practical issues with Macaroons: the caveat format is not standardized (both binary and allowed claim types), that matters a lot when using third party caveats. There are some de facto formats but they are full of issues (e.g. date format not exactly ISO).
Validation of a set of Macaroons requires walking a graph, that needs cycle detection, implementations that I've checked do not allow nested third party caveats, that invalidates one reason to use them.
Attenuation is nice but it doesn't play nice with third party caveats (hash is used as a key for decryption, appending to a third party caveat changes hash).
Then there are implementation errors such as: https://github.com/nitram509/macaroons.js/blob/master/lib/Cr...
Some of these issues could be removed by slightly changing implementations but the de facto implementation basically froze it. (then there is a fact that the de facto impl already changed some aspects from the paper, e.g. calculation of hash for appended third party caveat).
Wow what a treasure trove of goodness. Thank you!
You don't avoid it, you do it. Gathering simple user info including permissions should be the first step at the request boundary and it can traverse the life of the request. If you foolishly use a stateless token to read permissions, you're gonna be annoyed when changes you make don't take effect immediately. I trust your seniors know this (of course different situations and caveats apply, but this is referring to the general approach).
Most modern web frameworks will do this out of the box with a little configuration.
Specifically, I've had good results with Redis, applicable for the majority of web apps. In some rare cases where even local network is too slow, use of local memory storage has worked well (at the cost of greater memory usage and more complex invalidation procedures).
But before optimizing user permissions, in my experience there is much more to be gained from optimizing other types of DB queries.
The JOSE standards (of which JWT is a member) are error-prone and have had numerous critical security-affecting bugs due to how they were designed. [3]
To remedy that, I proposed PASETO. [4]
I still don't recommend PASETO for sessions, because of the arguments laid out in [1] and [2].
[1] http://cryto.net/~joepie91/blog/2016/06/13/stop-using-jwt-fo...
[2] http://cryto.net/%7Ejoepie91/blog/2016/06/19/stop-using-jwt-...
[3] https://paragonie.com/blog/2017/03/jwt-json-web-tokens-is-ba...
Also: PASETO is really fantastic, thanks for creating it! I've started mentioning it in my talks and using it for internal projects -- I really enjoy it so far =)
The industry will continue pay a dear price for mixing the rogue and unruly realm of web development, with what previously was a domain very conservative "enterprisey java development shops" where everybody dresses in a suit, and at least have some formal CS background above bootcamp course.
Imagine you're connecting to a service that uses JWT for sessions so they don't have to store anything server-side.
Let's say you have a token with an IAT of yesterday and and EXP of, say, a month from now.
Further, your browser gets infected with malware and the attacker steals your token. You rebuild your computer from a fresh install.
How does the service invalidate the token while still being stateless? It has 30 days left.
Your next move is:
> _
JWTs were designed to be single-use (or very, very short lived) claims (with optional cryptography features).
It was never meant to be "offload everything to the client and obviate the need for server-side storage". It was never meant to be the new hotness among the NoSQL Scalability crowd.
What if a user changes their password? Until that token hits its timing limit, they've got free reign. Or, you use denylists, requiring the database again.
More boilerplate Code and bandwidth but it works fine.
My issue with the article is that we’ve generally stopped building our own auth and now lean into using cognito or auth0 for authentication for the sites we build for third parties. Those services provide so much more out of the box then a home rolled solutions (MFA etc).
I see the value of signed tokens in complex infrastructure where you want to have one heavily guarded system doing the authentication and token assignment and then a bunch of other systems just validating the tokens.
Using random session cookies does not prevent you from using caches.
> In this media rich age, the data size argument is a bit silly.
JWTs aren't cached, and cookies are sent on every request, so there's a much bigger multiplier on JWT size cost than there is on media size cost.
So when would you use session tokens? When you have a small application that you confidently predict will never outgrow being a monolith.
That's true. JWT is great for WebSocket connections because you can make the expiry really short (you could even make it 1 minute) and you could re-issue a new token in real-time every 50 seconds just before the previous one expires. Then if the user goes completely offline for 1 minute, then they lose their session (the JWT becomes invalid).
For stateful CRUD applications that don't need to scale, and have a centralized authority, by all means, use session cookies.
If, on the other-hand you have a application that needs multiple authentication sources, has a API on the other end that doesn't want to know a separate authentication path, or run stateless functions, JWT is a fairly good choice.
For most modern applications, session cookies create far more problems then the simple universal decision to use JWT across the board.
But SPA applications (and, for that matter, classic AJAX applications) have been making small, frequent API requests for 15 years. There is a standard solution to the problem of repeated session database lookups: caching. And in the unlikely instance of an application with significant enough usage that session lookups are problematic but no preexisting caching strategy, the standard answer here is simply to move sessions to a fast lossy database like Redis.
All the previous problems with JWTs remain in play in the author's "good" example.
There are better reasons to avoid JWT than are provided in this article, but it does a fine job of communicating the fundamental nut of the problem. You can easily do better, both for performance and for security, than JWT does. Chances are, your framework's existing session store already is better than JWT. Rails, for instance, has had stateless signed cookies for something like a decade.
We recommend you avoid JWT. If you want to be cool and use a non-default session token format, look into Macaroons.
Some notes for this blog post:
- It does not cover the worst issue with JWT (IMO): you don't get revocation by default. Some vendors use JWTs and still have revocation, but they do this via CRL management. CRL management is not easier than a session in a database.
- In the context of OAuth2, JWT is often a bearer token. This introduces a number of subtle flaws that OAuth1.0a did not have. Notably, in OAuth 1.0a, if I steal your credential for service X, I can't do anything with that without also having service X's credential. In OAuth2.0, it's a bearer token, so game over. You could argue this is an OAuth2.0 flaw -- or perhaps not even an OAuth2 flaw, because OAuth2.0 doesn't force you to do this. But OAuth2 and JWT make it the obvious choice, and so this model is now ubiquitous.
- It uses the phrase "signing" a lot. In JWT, signing usually means MACing, specifically with HMAC-SHA256. in other contexts "signing" often means using asymmetric cryptography: a separate verification and signing key. JWT supports both -- because JWT, in its folly, supports everything.
> It’s important to note that I don’t hate JWTs. I just think they’re useless for a majority of websites.
...and lays out a nuanced perspective of when they're an improvement over cookies at the end.
His use case at the end is describing microservice architecture. Microservice architecture is trending, ergo JWTs are trending. I don't see the problem.
Ah, yes, 2018, the Year Where Everything On The Internet Is Connected To A Cable.
It's 24 MB of bandwidth to the -server-. Your server -better- be behind a decent broadband connection, or what are you even doing?
1/3rd a kilobyte per page request to the -client-. 1/3rd a kb is a blink of an eye even on modern dialup.
Many people are on cell phones with low data limits. A "few MB", let's say 3MB == a few, represents 0.1% of someone's data limit. Sure, it's not that much on its own, but it adds up.
Likewise, a few seconds of CPU time is fine if you're on the latest iPhone, but if you're in a developing country on an inexpensive Android phone that few seconds of CPU time is going to turn into a world of hurt.
This cavalier attitude towards bandwidth and CPU time is outright hostile to certain classes of users.
I was objecting to the "It's 2018 and you're complaining about a few MB of bandwidth and a few seconds of CPU time?" statement, not the technical detail of JWT adding an extra ~240 bytes.
I've seen statements similar to this applied to everything from big JavaScript libraries to large "Hero Images" to 2MB GIFs embedded in pages. It's a poor argument and it's representative of an attitude that's hostile to users.
tl;dr, remember the 500ms overall budget for the humans at the end of the pipeline. No one anywhere said I want my response time slower.
You are hitting the database anyways reason applies to a limited subset of of use cases.
Sessions are simplier use them on multipage websites. SPA or apps jwt is perfect.
But honestly I don't see the need for the vast majority of applications. Most frameworks cache the permissions, etc on login so the database doesn't have to be accessed on every request.
No. What? No.
You can't compare a signed JWT with a bare user ID. The proper comparison is a signed JWT vs. a cryptographically random session identifier with sufficient entropy. It's still smaller than the JWT, pretty much by definition, but make the right comparison, please.
So he admits that the signed part is the tradeoff. But I totally agree with you, barely mentioning that, when that's the whole point (JWTs are used for authentication/authorization, not just easily faked identification), is incredibly disingenuous. Never identify users on the client side with something that isn't cryptographically secure. Somewhere, you or another developer will end up implicitly believing that ID is trustworthy, and you just introduced a critical security flaw.
First memcache and then Redis sessions were a continuous centeralized source of failure we could remove, and honestly didn’t scale very cleanly approaching millions of users.
Removing moving parts from our stack was a major win.
That’s not to say JWT is without thorns, but overall it’s better than a centeralized point of failure.
We go from about 25,000 request a second during the day to 200 at night, and there was no good way we could find to autoscale it.
We scripted the build up process based on time and sometimes it wasn't meeting demand.
It was taking a lot of devops time. I'd had an experimental fork of our application using JWT floating around for a while and my manager made it a priority. It's never needed any maintaince and had been a real improvement for us.
Same happens on reset password, where by the book you need to sign out the user from every device. Good luck with that having standard JWT implementation.
The point is that you have two tokens, one a refresh token and one a stateless token. You revoke the refresh token on the server, which means the next refresh attempt will fail.
Still, an hour is a LONG TIME when a session could just kill all requests immediately for a user.
- allowing security questions to reset passwords
- allowing sms resets of passwords
- allowing sms 2-factor in combination with sms resets
I understand that my company is largely at fault for enabling these, but it's scary that they're even options. It's also pretty stupid that their password requirements are 8 characters, mixed case, and at least 1 number.
And while I agree that the things you brought up don't meet my personal standards for security, there are many organizations where those features are acceptable given their use case.
Keep in mind that I don't endorse that approach! Just giving an example of a narrow case where that applies.
That said, I appreciate your feedback and will personally take your feedback to our product group.
Thanks for taking my feedback to your group. I hope it helps.
Naturally, as a company that specializes in security, we have a unique threat model and do not allo SMS resets of passwords, security questions, etc for our organization.
If you're genuinely interested in learning more, I'd suggest looking at our security certifications: https://www.okta.com/security/ or reading the blog posts by our in-house security team: https://www.okta.com/security-blog/
A typical GET request involves multiple headers, including cookies. Cookies are sent for every request for any resource for a given domain. The more cookies you have, and the bigger they are, the bigger your request. The bigger your request, the more likely it is to take longer to send and receive it. The more of them you send, the more latency accumulates.
When The Cookie Crumbles https://yuiblog.com/blog/2007/03/01/performance-research-par...
Reduce Cookie Size https://developer.yahoo.com/performance/rules.html#cookie_si...
Performance Limits https://stackoverflow.com/a/6963585
Here's how this goes:
When a user authenticates, the system sends them a public key encrypted blob inside a cookie. When the user makes further HTTPS requests the blob will be sent back, the system can decrypt it with the private key and get back the data inside. Components of the system would squirrel away per-user data inside this blob and so the cookie might get updated as they surfed around the site or did things.
One day, people behind a local component using this contraption asked me for some "advice". They'd "filled up" the blob and there didn't seem to be a way to add more data but they needed to store something else, I worked for a different part of the company but I knew about cryptography, what should they do now? They'd found that there didn't seem to be a "cipher mode" option for public key cryptography...
And so that's the point where I couldn't decide whether to laugh or cry, after that I spent a few hours on international conference calls basically telling people that they're idiots and nobody should have even _designed_ this let alone built it.
Part way through that I explained that encryption doesn't magically mean bad guys can't change the inside of the blob AND that it doesn't magically prevent bad guys from stealing blobs they found in one place and using them elsewhere. So what is this even for? In mitigation the engineers who built it explained that, er, actually the first thing they do with the blob after decrypting it is to check their session database to ensure all the data matches up, if not it's invalid and the user just gets logged out silently. Thus, at the end of the day, it's just functioning as a session ID checked against a database anyway. All this cryptographic effort is in fact completely wasted and achieves nothing in practice except to make the system far more complicated and fragile. Brilliant. /facepalm
If you are transmitting metadata about some item, such as a song or a video, that’s one thing, but when it’s user info and the payload is not encrypted, you end up essentially leaking that data.
Other issues arise when you throw in logging and crash reporting - you may not even realize that that JWT session token just got logged and now you have user data where it doesn’t belong.
If you think you need JWTs or similar tech, you don't need JWTs or similar tech.
What's the headache about minting tokens? You create a new uuid() on the server, store it in the DB in its own table which has references to accounts, keep an isValid field next to it for server-side invalidation, and store it in localStorage in the client. Is there a security flaw or something in this?
Generating a sufficiently (16-32 bytes) long string of randomness and using just that as a session ID stored in a database is a perfectly fine technique, scales well enough and is quite hard to get wrong.
Most startups and projects never hit this size, they usually fold before that level of growth. It is much lower than one would assume though since every request made to an API has to do the lookups etc.
If your data store(s) can't handle the load of looking up a ~32 byte token (that is, if you are sane and not using JWT), then how exactly are they supposed to hold up to whatever your business logic part of the app is doing?
As an attacker, if I have successfully injected my JavaScript code into your webpage, I can make HTTP requests on your server to do whatever I want with that user's account (their cookie containing their Session ID will automatically be attached to those malicious requests; so they will look like real requests from that user).
And yes, this attack also works with httpOnly cookies; I don't need to be able to read the cookie in order to use it.
The httpOnly flag is practically useless; I don't think any hacker worth their salt would want to steal session IDs for later use (session IDs and JWTs have a way of expiring quite quickly); usually with an XSS attack, you want to do the attack in-place from inside the victim's own browser.
I've even read security reports by supposedly reputable security consultants also claiming that JWTs are bad but their arguments are hand wavy and make no sense.
>> Let’s say that your website gets roughly 100k page views per month. That means you’d be consuming an additional ~24MB of bandwidth each month.
Negligible.
>> You’re Going to Hit the Database Anyway
Yes, but less often. So your DB will be able to service more users overall. For some use cases, we're talking orders of magnitude more users.
If a trusted machine with a privileged token on it is compromised somehow, it will likely take the attacker some time to search for and discover the token. If you use centralized auth and you realize there was a breach before this happens (say from monitoring/anomaly alerts), you can revoke the token and prevent unauthorized access. If your token is JWT and it doesn't expire for another 45 minutes, you're in much worse shape.
This isn't the only factor to consider, but it's an important one.
https://auth0.com/blog/critical-vulnerabilities-in-json-web-...
https://blogs.adobe.com/security/2017/03/critical-vulnerabil...
These were critical vulnerabilities enabled by an error-prone cryptographic design that broke real systems.
Don't pretend it's hand-wavy.
No, these are vulnerabilities in the standard itself.
I outlined the arguments here: https://paragonie.com/blog/2017/03/jwt-json-web-tokens-is-ba...
It's an error-prone cryptographic design that needs to be replaced.
Blaming implementations for faithfully implementing a flawed standard is a stupid thing to do, since it doesn't solve their insecurity.
'The JWS Signature value is not valid if the "alg" value does not represent a supported algorithm'
Even if you did consider it a flaw in the RFC itself, the fact that there was a flaw once-upon-a-time with a specific aspect of JWT, doesn't invalidate the whole idea of JWTs.
I don't know any major standard that was perfect from day 1. This can be said about TCP/IP (e.g. IpV4 addresses were clearly a mistake). Also, I recall that there were flaws with HTTP1 and that's why HTTP1.1 was released soon after. The WebSocket protocol also went through MANY iterations.
There are use cases were JWTs are necessary. For example, I did some work with real-time presence (to get notifications when users go online or offline); to be able to get the username from the JWT instead of the database saves a lot of database queries and the code is much cleaner since you can check synchronously instead of having to wait. Also, you don't want to waste precious CPU time doing DB queries for connections that haven't been authenticated yet.
The premise that went into JWTs was not invalidated. Their design was proven by multiple incidents to be error-prone, so I sought to replace JWTs.
The result? https://paseto.io
(yes, you can store JWTs in cookies too, but that is kinda uncommon)
https://stormpath.com/blog/where-to-store-your-jwts-cookies-...
Respect to the author for trying to generate some content for the company blog, but the end result ultimately comes down to a relatively trivial decision in order to save a few bytes.
Or, if you want to have more immediate revokes without having a ridiculously short expiration time, keep a list of blacklisted tokens that you clear at least every <refresh time> seconds.
At the end of the day, JWTs still have to be accepted by the server, which you have complete control over.
Um. Yeah. Also completely insecure.
I know he mentions signed cookies shortly afterwards but the way that part of phrased seriously made me twitch, especially coming from an auth provider's blog.
I guess you could design a binary-first token format that’s smaller than JWT, that’s true.
Else I opt for the gateway pattern (a service handles authentication and then forwards requests to other microservices).
This sounds like a bug in someone's implementation of JWTs; most JWTs are not signed twice. It's thus not a valid criticism of JWTs.
> If you’re building a simple website like the ones described above, then your best bet is to stick with boring, simple, and secure server side sessions. Instead of storing a user ID inside of a JWT, then storing a JWT inside of a cookie: just store the user ID directly inside of the cookie and be done with it.
This is conflating two very different things. Sticking with boring, securing server side sessions… sure (though we're eliding how one would actually implement that, but let's assume it's by sending a sufficiently long, unguessable token in a cookie) but then we continue with "just store the user ID directly inside of the cookie" — no! The point of the JWT is the authenticate the user; just sticking a user ID into a cookie doesn't do that; the user could just change the ID in the cookie to whatever, and be done with it. I'd hope the author means "stick the user ID into the session-side storage" (that's associated with the client in some means, likely by an unguessable token as mentioned earlier), but earlier in the article we make the same mistake:
> If we store the ID in a cookie, our total size is 6 bytes
Except, no, you're going to need to store that server-side, and send a token, which will realistically be 16 bytes, not 6. The comparison mostly still stands, since there isn't a significant difference between 6 and 16 bytes.
> For storing a simple user session, that is a ~51x size inflation on every single page request in exchange for cryptographic signing (as well as some header metadata).
It's not a 51x size inflation on every request. That datum is 51x larger, but the request itself includes plenty of other things.
This concern will diminish greatly as HTTP/2 is adopted, I think: HTTP/2 is capable of compressing headers, but in addition to that, multiple requests sending the header can essentially say "let's call this header header #1 and then reference it w/ that number on subsequent requests, greatly reducing the transfer required for common, repetitive headers. If you're on AWS, ALBs support it, so it should be very accessible for most folks w/ browsers. (Client-side programming libraries are another thing, but it'll get there.)
> You’re Going to Hit the Database Anyway
The point is that you can hit the database one time less; yeah, you might need the user object, but you might not. But the suggested alternative of using server-side storage requires a DB lookup in addition to looking up the user object: we've got to first translate the session token in the cookie into a user ID, and then from there get the user object itself. (Perhaps you can, in some cases, JOIN these if you're using a relational DB; but it still bites you if you don't need the user object, and even if you do, the additional disk read isn't going to be faster than checking a signature.
If you're putting just the user ID in the cookie, and signing it, you're just re-inventing JWTs. Perhaps you'll save a few bytes, but you lose out on what are hopefully more robust, feature complete libraries, and a common, familiar format.
That's all the writer is saying, and I think he said it quite well.
O...M...G... I mean... Let me check again what year it is.
Please stop writing bullshit just because you can have a blog for free...