JWT / JWS / JWE
The self-contained token format: signed claims anyone with the public key can verify.
By the end of this lesson, read a JWT, explain how its signature is verified, and avoid the classic JWT security mistakes.
A JWT (JSON Web Token) is three base64url parts joined by dots: header.payload.signature. The header names the algorithm, the payload is a set of claims (JSON facts about the subject), and the signature lets a verifier confirm the token was issued by who it says and not modified.
Signed tokens are JWS. Encrypted tokens are JWE. Most bearer tokens you see are JWS — signed, not encrypted, so treat the payload as readable by anyone.
First, see the whole system. Then we’ll open it up.
Issue, carry, verify
- The issuer signs a JWT with its private key.
- The client sends it to the API as a bearer token.
- The API fetches the issuer's public keys from the JWKS endpoint and verifies the signature and claims.
flowchart LR idp[Issuer / IdP] -->|signs with private key| jwt[JWT] jwt -->|Authorization: Bearer| api[API] api -->|fetch public keys| jwks[JWKS endpoint] api -->|verify signature + claims| ok[Trust subject]
- Standard claims
iss(issuer),sub(subject),aud(audience — who the token is for),exp(expiry),iat(issued-at),nbf(not-before). Verifyingaudandexpis not optional.
This is where the abstraction starts leaking.
The payload is signed, not secret. Anyone can decode a JWS and read every claim. Never put secrets in a JWT. And never trust a claim you didn't verify the signature for — a decoded-but-unverified token is attacker-controlled JSON.
An API decodes the JWT to read sub but skips signature verification 'to save time'. Now craft a token with sub: admin. It works. Signature verification is the entire point.
alg=none / algorithm confusion
- Trigger
- A verifier accepts the token's declared algorithm, including
none, or confuses RS256 (asymmetric) with HS256 (symmetric) using the public key as an HMAC secret. - Symptom
- Attackers forge valid-looking tokens without the private key.
- Blast radius
- Complete authentication bypass — any identity, any claims.
- Mitigation
- Pin the expected algorithm; never accept
none; separate verification keys by algorithm.
Deep dive: Token Replay
Missing audience / expiry checks
- Trigger
- A token minted for service A is replayed to service B, or an expired token is honored.
- Symptom
- Cross-service token reuse or use of stale tokens.
- Blast radius
- Access to services the token was never intended for.
- Mitigation
- Always validate
aud,exp,nbf, andiss; keep clock skew tight.
Deep dive: Clock Skew
JWTs remove a per-request session lookup (great for latency and horizontal scale) but push key management (JWKS caching, rotation, kid handling) and the revocation problem onto you.
Can you store a user's credit card in a JWT if the token is signed?
No. Signing prevents tampering, not reading. A JWS payload is readable by anyone holding the token.