The server keeps the truth
A session login hands the browser a pointer and keeps the truth for itself.
On a successful login your server creates a record, mapping a session identifier to a user, an expiry, maybe a device and an address. It puts that identifier in a cookie marked unreadable by script, secure, and limited to your own site.
The identifier means nothing by itself. It is 128 bits of randomness, and every fact lives on your side. Each request looks the record up, which against an in-memory store costs well under a millisecond.
Buy the property that token systems sweat for: immediate, total control.
Logging out deletes a row. Logging out everywhere deletes every row for that user. Banning an account, resetting a phished password, killing a stolen cookie, all take effect on the very next request, because your server consults its own state every single time.
Show your users their active sessions per device while you are at it, the screen that sits in the security settings of every large product. That is impossible to do honestly when your server keeps no records.
The scaling objection
Weigh the traditional objection, smaller than its reputation. With several app servers you either pin each user to one machine, or you share one session store between them. Pinning is fragile, because draining a machine logs its users out, so nearly everyone shares the store.
One in-memory instance absorbs tens of thousands of session reads a second without noticing. It does become a dependency on your request path, so give it first-tier treatment: replication, failover, and an answer for what happens during a blip.
Take it as the boring default for a server-rendered app, because your framework already assumes it and ships the middleware pre-wired. It is the simplest design that gives your security team the revocation guarantees they will eventually demand.
Worked example
In September 2018, Facebook disclosed that a bug chain in the View As feature had let attackers steal access tokens for as many as 50 million accounts. The response is the part worth studying: Facebook invalidated the tokens of the 50 million affected accounts plus another 40 million as a precaution. Ninety million people were logged out by what was operationally a bulk delete, and every stolen credential died at that instant. That kill switch only exists because Facebook's tokens are checked against its own systems on use, the session model's defining property, rather than being self-contained signatures that stay valid until an expiry date. News coverage focused on the breach itself; the system design lesson is that when credentials point at server state, revoking 90 million of them is one operation.