# Stop using JWTs (samsch gist)

A short, blunt gist by GitHub user `samsch` arguing that [[jwt-for-sessions|JWTs should not be used for keeping users logged in]]. They aren't designed for it, the spec family has a poor security track record, and there's a much better tool that already exists: [[cookie-session-auth|regular cookie sessions]]. The gist is widely linked in web-auth threads as the short-form rebuttal to the JWT-for-sessions pattern. It cites longer pieces by joepie91 and Paragon Initiative as the deeper reading.

## The core argument

Four reasons the gist gives for not using JWTs as session tokens:

1. **Lifetime mismatch.** The JWT spec is designed for very short-lived tokens (~5 minutes or less). Sessions need longer lifespans. Stretching JWTs to fit means building revocation, rotation, and lifetime management — features the spec deliberately doesn't provide.
2. **"Stateless" auth isn't real.** You cannot securely have stateless authentication without massive resources (revocation lists, rotation, blocklists for compromised tokens). Once you accept you need a store, you might as well store everything and use a regular session ID. samsch links to a sister gist titled "Stateless is a lie."
3. **JWTs as session tokens are strictly worse than cookie sessions.** A JWT containing only a session ID is bigger, slower, and less flexible than a session cookie. It buys nothing.
4. **The JWT spec is distrusted by security experts.** The original spec made `alg: none` forgeries possible. The JOSE family has had repeated implementation footguns. samsch's takeaway: this should preclude all use of JWTs for security-related purposes. Links Paragon's deeper takedown.

## Don't use localStorage for credentials

Tangentially: don't use `localStorage` or `sessionStorage` to hold authentication credentials, including JWTs. Cited reference is Randall Degges' 2018 piece on the topic. The reason cookie-based session storage isn't replaceable by JS-accessible storage is XSS exposure: any script that loads in your origin can read every entry in `localStorage`. `HttpOnly` cookies cannot be touched by JS at all.

## Rebuttals

The gist ends with three pre-empted objections:

- *But Google uses JWTs!* — Google does **not** use JWTs for browser sessions. They use regular cookie sessions. Google's JWTs are SSO transports — short-lived bearer tokens that move a login from one host to another. That's within the reasonable use cases for JWTs, and Google has the security resources to implement it carefully. Their JWT usage isn't yours.
- *But stateless is better!* — See the "Stateless is a lie" companion gist. You can't have truly stateless auth at any reasonable security level.
- *I don't know how to set up sessions!* — Sessions don't have many recent articles because the technology isn't new. Most web frameworks ship session middleware. For Express, use `express-session` with a store connector like `connect-session-knex` against Postgres/MySQL/SQLite.

## When JWTs (or PASETO) are appropriate

The gist concedes that signed short-lived tokens have legitimate uses — SSO transports, password-reset links, email-verification links, capability tokens that expire in minutes. For those, samsch points to [[paseto]] as the better-designed, less-footgun successor to the JOSE family. Stop using JWTs even there if you can; if you can't, prefer PASETO.

## Why this gist gets cited so often

Because the JWT-as-session pattern is the default in countless tutorials and bootcamp curricula, and the case against it has to be repeated constantly. samsch's gist is the short, link-friendly version of the longer joepie91 + Paragon pieces, which is why it ends up pasted in pull-request reviews and Reddit threads year after year.
