JWT (JSON Web Token) is the most widely used token format for authentication and authorization in modern web applications. When you log into any web app and see a Bearer token in the Authorization header โ that's almost certainly a JWT. Understanding how to read and debug JWTs is an essential skill for every developer.
JWT Structure: 3 Parts Separated by Dots
A JWT looks like: xxxxx.yyyyy.zzzzz
- Header (xxxxx): Base64url encoded JSON. Contains token type ("JWT") and signing algorithm (HS256, RS256, etc.)
- Payload (yyyyy): Base64url encoded JSON. Contains claims โ user ID, roles, expiry, issued-at time, etc.
- Signature (zzzzz): HMAC or RSA signature of header + payload. Ensures the token wasn't tampered with.
Standard JWT Claims (Payload)
| Claim | Full Name | Description |
|---|---|---|
| iss | Issuer | Who issued the token (your auth server URL) |
| sub | Subject | User ID or entity the token is about |
| aud | Audience | Intended recipient(s) of the token |
| exp | Expiration | Unix timestamp when token expires |
| iat | Issued At | Unix timestamp when token was created |
| nbf | Not Before | Token not valid before this timestamp |
| jti | JWT ID | Unique identifier to prevent replay attacks |
How JWT Authentication Works
- User logs in with username/password
- Server validates credentials, creates JWT with user claims, signs it with secret key
- JWT sent to client (stored in localStorage or httpOnly cookie)
- Client sends JWT in every subsequent request:
Authorization: Bearer <token> - Server verifies signature without hitting database โ stateless authentication
- Server reads claims from payload to know who the user is and what they can do
Common JWT Security Mistakes
- Algorithm confusion attack: Never accept "alg: none" or allow the client to specify the algorithm. Hardcode expected algorithm server-side.
- Storing in localStorage: Vulnerable to XSS. Use httpOnly cookies for production apps.
- Weak secret keys: HS256 secrets should be at least 256 bits (32 random bytes). Never use predictable strings.
- No expiry: Always set
expclaim. Access tokens: 15 minutes. Refresh tokens: 7โ30 days. - Sensitive data in payload: JWT payload is only Base64 encoded โ anyone can decode it. Never put passwords, PII, or secrets in JWT payload.
exp timestamp in human-readable format so you know if the token is expired.