JWT Structure
A JWT is three Base64URL-encoded parts separated by dots:
1. Header (red)
2. Payload (green)
3. Signature (blue)
The signature ensures the header and payload were not modified. If any bit of the header or payload changes, the signature becomes invalid.
⚠️ Payloads Are NOT Encrypted
Base64URL encoding is not encryption — anyone can decode a JWT and read the payload. Never put passwords, credit card numbers, or sensitive PII in a JWT payload. Use JWE (JSON Web Encryption) if you need to encrypt the payload.
How JWT Authentication Works
- User logs in: Client sends credentials (username + password) to the server.
- Server issues JWT: Server verifies credentials, creates a JWT with user ID and claims, signs it with the secret key, returns it to the client.
- Client stores JWT: Typically in memory, localStorage, or an HttpOnly cookie.
- Client sends JWT with requests: Every API request includes the JWT in the
Authorization: Bearer <token>header. - Server verifies JWT: Server recomputes the expected signature. If it matches, it trusts the claims — no database lookup needed. If it does not match or the token is expired, the request is rejected.
JWT vs Session Authentication
| Feature | JWT (Stateless) | Session (Stateful) |
|---|---|---|
| Server storage | None — token is self-contained | Session stored in DB/Redis |
| Scalability | Excellent — any server can verify | Requires shared session store |
| Revocation | Hard — must use blocklist or short TTL | Easy — delete session from store |
| Token size | ~200–500 bytes (sent every request) | Small session ID cookie (~20 bytes) |
| Best for | Microservices, APIs, mobile apps | Traditional web apps, monoliths |
| Logout | Complex (need blocklist) | Trivial (delete session) |
HS256 vs RS256 vs ES256
| Algorithm | Type | Key | Use When |
|---|---|---|---|
| HS256 | Symmetric (HMAC) | Single shared secret | Single service — only one verifier |
| RS256 | Asymmetric (RSA) | Private key signs, public key verifies | Multiple services need to verify tokens |
| ES256 | Asymmetric (ECDSA) | Smaller key, same security as RS256 | Mobile/IoT where key size matters |
Standard JWT Claims
| Claim | Full Name | Purpose |
|---|---|---|
| iss | Issuer | Who issued the token (e.g. "api.example.com") |
| sub | Subject | Who the token is about (user ID) |
| aud | Audience | Who should accept the token |
| exp | Expiration | Unix timestamp when token expires |
| iat | Issued At | Unix timestamp when token was created |
| jti | JWT ID | Unique ID — used for token blocklisting |
| nbf | Not Before | Token not valid before this timestamp |
JWT Security Best Practices
- Always verify the signature — never trust a JWT without verifying it
- Set short expiry — 15 minutes for access tokens; use refresh tokens for longer sessions
- Use RS256 for multi-service architectures — never share your signing private key
- Store in HttpOnly cookies — prevents XSS from reading the token
- Validate the
audclaim — ensures the token was issued for your service specifically - Use
jtifor revocation — store revoked JTIs in Redis for logout functionality - Never put sensitive data in payload — payload is readable by anyone who has the token
💡 Decode Any JWT Instantly
A JWT's payload is just Base64URL-encoded JSON. You can decode it with any Base64 decoder. For debugging, paste your JWT into jwt.io (use only non-sensitive tokens — never paste production tokens into third-party tools).
How We Research and Update This Guide
We test the underlying formula or workflow, compare outputs with reliable references, and revise examples whenever the page content changes.
- The workflow or formula is tested directly in the tool and compared against independent reference examples.
- Examples are kept practical so readers can verify the result without hidden assumptions.
- Pages are revised whenever the interface, calculation flow, or surrounding guidance materially changes.
Frequently Asked Questions — JWT
A JWT (JSON Web Token) is a compact, self-contained token that encodes a JSON payload and signs it cryptographically. It is used mainly for authentication and authorisation: after a user logs in, the server issues a JWT. The client sends this token with subsequent requests (usually in the Authorization header). The server verifies the signature — if valid, it trusts the claims inside without a database lookup.
No — by default, JWT payloads are only Base64URL-encoded, not encrypted. Anyone who obtains a JWT can decode and read the payload. You should never put sensitive data (passwords, credit card numbers, PII) in a JWT payload. If you need to encrypt the payload, use JWE (JSON Web Encryption). The signature only proves the token was not tampered with — it does not hide the contents.
HS256 uses a single shared secret key for both signing and verification (HMAC-SHA256). Both the issuer and verifier must have the same secret — fine for a single server, risky if you share tokens across services. RS256 uses an asymmetric RSA key pair: the private key signs, the public key verifies. Any service can verify tokens using the public key without knowing the private key. RS256 is preferred for microservices and third-party token verification.
JWTs are stateless — the server has no record of issued tokens, so there is no built-in invalidation. Common approaches: (1) Short expiry (15 min) + refresh tokens — limit the damage window. (2) Token blocklist — store invalidated JWT IDs (jti) in Redis; check on each request. (3) Version field — store a "token version" per user in the database; increment it on logout; verify it matches. Each approach adds statefulness back, trading scalability for control.
The safest option is an HttpOnly cookie — JavaScript cannot read it, protecting against XSS. localStorage is convenient but readable by any JS on the page — vulnerable to XSS attacks. sessionStorage is similar to localStorage but cleared on tab close. The common recommendation: store access tokens in memory (JS variable), store refresh tokens in HttpOnly cookies. This balances security and usability.
OAuth is an authorisation framework — a protocol for delegating access (e.g. "Login with Google"). JWT is a token format — a way to encode and sign claims. OAuth often uses JWT as its token format (OAuth 2.0 access tokens are commonly JWTs). They solve different problems: OAuth defines the flow of how tokens are obtained; JWT defines what the token looks like and how it is verified.