A JSON Web Token (JWT, defined in RFC 7519) is a compact way to pass a signed set of claims between two parties — most commonly a client and an API, as proof that the bearer already authenticated. It's the default building block behind most modern session and API auth flows.
Anatomy of a JWT
A JWT is three Base64URL-encoded segments joined by dots: header.payload.signature.
- Header — a small JSON object naming the signing algorithm and token type, e.g.
{"alg":"HS256","typ":"JWT"}. - Payload — the claims: arbitrary data plus a set of registered fields like
sub(subject),iss(issuer),aud(audience),iat(issued at),exp(expiry), andnbf(not valid before). - Signature — computed over the header and payload using the algorithm from the header and a secret or private key. It proves the token wasn't altered after issuance.
Crucially, the header and payload are only encoded, not encrypted. Anyone can decode and read them without any key — the signature only protects integrity, not confidentiality. Never put secrets you don't want the token holder to read directly into the payload.
HMAC vs. RSA vs. ECDSA signing
HMAC (HS256/384/512) is symmetric: the same secret both signs and verifies the token. It's fast and simple, but every service that needs to verify tokens must also hold the secret — which means every one of them could also forge tokens.
RSA (RS256/384/512) and ECDSA (ES256/384/512) are asymmetric: a private key signs, and a separate public key verifies. This is the right choice whenever multiple independent services need to verify tokens issued by one authority — each service only needs the public key, which is safe to distribute. ECDSA produces shorter signatures than RSA at an equivalent security level, at the cost of being slightly less universally supported.
Common JWT security mistakes
- Trusting the decoded payload without verifying the signature. Decoding is not the same as validating — always verify server-side before trusting any claim.
- Accepting
"alg": "none"or letting the client choose the algorithm. A server should pin the expected algorithm rather than trusting whatever the token header claims. - Storing tokens in
localStoragemakes them readable by any script on the page — vulnerable to XSS. An httpOnly, secure cookie is generally safer for browser-based apps. - Long-lived access tokens with no revocation path. Short expirations paired with a refresh-token flow limit the damage of a leaked token.