What Is a JWT?
A JSON Web Token (JWT) is a compact, URL-safe token format for transmitting claims between two parties. JWTs are widely used for authentication and authorization in web applications and APIs.
JWT Structure
A JWT has three parts separated by dots: header.payload.signature
Header
{
"alg": "HS256",
"typ": "JWT"
}
Specifies the signing algorithm (HS256, RS256, ES256, etc.).
Payload (Claims)
{
"sub": "user-42",
"name": "Alice",
"iat": 1672531200,
"exp": 1672534800
}
Standard claims: sub (subject), iss (issuer), exp (expiration), iat (issued at), aud (audience), nbf (not before), jti (unique ID).
Signature
HMACSHA256(
base64UrlEncode(header) + '.' + base64UrlEncode(payload),
secret
)
The signature ensures the token hasn't been tampered with.
Signing Algorithms
| Algorithm | Type | Key | Use Case |
|---|---|---|---|
| HS256 | Symmetric | Shared secret | Single-service apps |
| RS256 | Asymmetric | RSA key pair | Distributed systems |
| ES256 | Asymmetric | EC key pair | Modern systems (smaller keys) |
HS256: Both parties share the same secret. Simple but the secret must be distributed to every service that validates tokens.
RS256/ES256: The issuer signs with a private key. Validators verify with the public key (available via JWKS endpoint). Better for microservices.
Validating a JWT
Always validate:
- Signature — Verify using the correct key/algorithm
- Expiration (
exp) — Reject expired tokens - Issuer (
iss) — Ensure it's from a trusted source - Audience (
aud) — Ensure the token is intended for your service - Algorithm — Reject
noneand unexpected algorithms
Common Pitfalls
1. The `alg: none` Attack
Attackers set the algorithm to none, bypassing signature verification. Always enforce an explicit algorithm allowlist on the server.
2. Algorithm Confusion
If your server expects RS256 but an attacker sends HS256, the public key may be used as the HMAC secret. Explicitly check the algorithm.
3. Not Checking Expiration
A JWT without exp is valid forever. Always set and check expiration.
4. Storing Sensitive Data in the Payload
JWT payloads are Base64-encoded, not encrypted. Anyone can decode and read them. Never put passwords, SSNs, or secrets in a JWT.
5. No Revocation Mechanism
JWTs are stateless — you can't revoke them once issued. Mitigate with:
- Short expiration times (15 minutes)
- A token blacklist for logout
- Refresh token rotation
Best Practice
Use short-lived access tokens (15 min) with refresh tokens (7 days). Use RS256/ES256 for distributed systems. Always validate all claims.