Stop using JWTs (samsch gist)
- title
- Stop using JWTs (samsch gist)
- type
- summary
- summary
- Long-circulating gist arguing JWTs are wrong for sessions; use cookie sessions, and use PASETO for the rare short-lived-token cases
- tags
- authentication, security, web
- sources
- samsch-jwt-auth-gist
- created
- 2026-04-25
- updated
- 2026-04-25
A short, blunt gist by GitHub user samsch arguing that 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: 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:
- 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.
- "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."
- 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.
- The JWT spec is distrusted by security experts. The original spec made
alg: noneforgeries 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-sessionwith a store connector likeconnect-session-knexagainst 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.