⚡ News

JWT is a Scam: Why Your App Doesn't Need Stateless Auth

JWT is a Scam: Why Your App Doesn't Need Stateless Auth

I am tired of pretending JWT is fine. It isn't. It's a cargo cult. It solves a problem your app almost certainly does not have, it creates four or five problems your app definitely does have, and a generation of backend developers has been bullied into shipping it because some blog post in 2014 said "stateless" like it was a virtue instead of a tradeoff. Every JWT-based system I've audited has the same broken revocation story, the same useless refresh dance, and the same client codebase that decodes the payload and trusts it. People are still shipping the same mistakes six years after these flaws were first publicized.

If you're building a web app, a mobile app, or a first-party API: JWT is the wrong default and you should stop reaching for it. A row in Postgres with a bearer token in front of it is faster, simpler, and strictly more secure. A JWT is three base64url segments — a header, a JSON payload, a signature. The signature is either an HMAC or an RSA/ECDSA signature. The pitch is: the server signs it, the client carries it, every subsequent request only needs a signature verification — no database round-trip. Stateless authentication is the entire value proposition.

The fatal flaw is that you cannot invalidate a JWT before its expiration (exp). To do so, you must store the JTI server-side in a revocation list and check that list on every single request. This reintroduces the database lookup that JWT was supposed to skip. You've essentially reinvented sessions, but badly. This leaves developers with two losing moves: either don't invalidate (leaving compromised tokens valid until expiration) or maintain a revocation list (paying for both JWT complexity and session lookup costs). There is no third option. Refresh tokens are simply a confession of this inherent structural failure.

↗ Read original source