Suppose the requirement is to keep users logged in after closing their browser, while allowing each device to be logged out separately. Where should a JWT or session ID live? localStorage, sessionStorage, and cookies each have tradeoffs. Persistence in one browser is separate from logging in on another device; a storage choice alone does not provide cross-device authentication.

So I compared four representative options and thought through why things ultimately settle on a single approach. Session information is, in effect, a hotel room key. Where do you keep it, and who can deactivate it? Look at it through those two questions and things get surprisingly tidy.

The Four Options

First, there is putting a JWT in localStorage. The value survives closing the browser, so on persistence it's flawless. But its contents are fully visible to JavaScript, which makes it terribly weak against XSS (cross-site scripting).

If a malicious script runs even once, the token walks out the door that very moment. It's like hiding your key under the potted plant in the hallway. If you care about security at all, this one is the first to go.

Another option is a JWT in an HttpOnly cookie. Setting Max-Age or Expires allows persistence after the browser closes. HttpOnly prevents JavaScript from reading the value directly, but does not stop injected scripts from performing authenticated actions. Each cookie attribute protects a different part of the interaction.

Revocation is the operational concern. A design that checks only a JWT’s signature and expiry has difficulty logging out a particular device immediately. It resembles a guest carrying a spare key absent from the front desk’s register. A revocation list or session lookup can provide that control, at the cost of server-side state and management.

A third option is a session ID in an HttpOnly cookie. Cookie expiry controls persistence, while Secure restricts transmission to HTTPS. Preventing direct access to the value and preventing XSS itself remain separate concerns.

Where it particularly shines is operational flexibility. The session itself lives on the server in Redis or a DB, so the server can invalidate it whenever it sees fit. It's the key card the front desk can wipe. Listing the devices currently logged in, or destroying every session when the password changes, becomes a trivial matter.

Finally, a JWT can be stored in sessionStorage. It normally disappears when its tab closes, making it unsuitable for this persistence requirement. Like localStorage, it is readable from JavaScript.

Laid side by side, they look like this.

StoragePersistence after browser closureDirect JavaScript accessServer-side revocation
localStorage + JWTPossibleYesRequires a revocation lookup or similar state
HttpOnly cookie + JWTDepends on cookie expiry settingsNoRequires a revocation lookup or similar state
HttpOnly cookie + session IDDepends on cookie expiry settingsNoInvalidate the stored session
sessionStorage + JWTNormally until the tab closesYesRequires a revocation lookup or similar state

Why the Session ID Wins

For a typical web application that needs logout and device management, I would choose an HttpOnly cookie with a server-managed session ID. It makes storage protection and control after issuance easier to consider together. There are three reasons.

First, HttpOnly prevents direct reads by scripts. Second, invalidating the server-side session can stop access on the next authentication check. JWTs can also support revocation, but this arrangement keeps revocation within session management.

The third is device management. When a user is logged in on several devices, each session can be listed and deleted individually. That strength comes precisely from keeping state on the server.

Before choosing a JWT in localStorage for scalability, consider forced logout as well. Without a revocation mechanism, the system must wait for issued tokens to expire. Asking the front desk to recover spare keys is difficult when there is no register of them.

These four options differ in both storage and revocation. For this use case, I want to limit direct access to the credential and retain control after it has been issued. Cookies with server-side sessions make both concerns manageable. A key needs a revocation plan as well as a storage location.