What a JWT is not
Signed, not encrypted. Stateless, which is the feature and the problem. And revocation, which you have to add back yourself.
A JWT is a base64 payload with a signature. Anyone holding it can read every claim inside. It is not encrypted, and putting anything sensitive in the payload is publishing it. The signature proves the server issued it and it has not been altered, which is a real and useful guarantee, and it is the only one on offer.
Statelessness is the selling point: any instance can verify a token without a database lookup, which is genuinely valuable across services. The consequence is that a valid token stays valid until it expires, whatever happens in between. Ban a user, change their role, log them out on another device: the token in their pocket does not know. The standard patch is short-lived access tokens with a refresh token you can revoke, which reintroduces the server-side state you were avoiding and is usually still the right call.
On storage: localStorage is readable by any script on the page, so one XSS is one stolen token. An HttpOnly cookie is not readable by script, which trades that risk for CSRF, which SameSite and a token pattern handle. For a normal web application talking to its own backend, a session cookie is simpler and safer than a JWT, and choosing the JWT because it is what tutorials use is a decision you should be able to justify with something else.
You should now be able to
- Explain what a signature guarantees and what it does not
- Describe why an issued token cannot easily be cancelled
- Decide where a token should be stored in a browser
Loading…