JSON Web Tokens (JWTs) are one of the most widely used authentication mechanisms in modern web applications — and one of the most commonly misunderstood. Every developer working with APIs, single-page apps, or microservices will encounter JWTs. Understanding how they work (and what they don't do) is essential for building secure applications.
Use our JWT Decoder to inspect any JWT and see its header, payload, and signature in readable format.
What Is a JWT?
A JWT is a compact, URL-safe token that contains a JSON payload with claims (statements about the user or session). It is digitally signed so the recipient can verify that it was issued by a trusted party and has not been tampered with.
A JWT looks like this:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5cIt has three parts separated by dots:
- Header: Algorithm and token type (e.g., HS256, RS256)
- Payload: Claims — user ID, roles, expiration time, etc.
- Signature: Cryptographic signature that verifies the token's integrity
How JWT Authentication Works
- User logs in with username/password.
- Server verifies credentials and creates a JWT containing the user's ID, roles, and an expiration time.
- Server signs the JWT with a secret key (HMAC) or private key (RSA/ECDSA) and returns it to the client.
- Client stores the JWT (typically in memory or an httpOnly cookie) and sends it with every subsequent API request in the Authorization header:
Authorization: Bearer eyJhbG... - Server receives the request, verifies the JWT signature, checks expiration, and extracts the user's identity from the payload — without querying a database.
This is the key advantage of JWTs: stateless authentication. The server does not need to store session data or query a database on every request — the JWT itself contains all necessary information.
Standard JWT Claims
| Claim | Name | Purpose |
|---|---|---|
| iss | Issuer | Who issued the token (your auth server) |
| sub | Subject | Who the token is about (user ID) |
| aud | Audience | Intended recipient (your API) |
| exp | Expiration | Unix timestamp when the token expires |
| iat | Issued At | Unix timestamp when the token was created |
| jti | JWT ID | Unique identifier for this specific token |
You can add custom claims (user roles, permissions, tenant ID) in the payload alongside these standard claims.
JWT vs Server-Side Sessions
| Feature | JWT | Server Sessions |
|---|---|---|
| Storage | Client-side (no server state) | Server-side (database/Redis) |
| Scalability | Excellent (any server can verify) | Requires shared session store |
| Revocation | Difficult (token valid until expiry) | Easy (delete session from store) |
| Size | Larger (payload is in every request) | Small cookie (session ID only) |
| Best for | APIs, SPAs, microservices | Traditional server-rendered apps |
JWT Security Pitfalls
- Never store JWTs in localStorage: localStorage is accessible to any JavaScript on the page, making it vulnerable to XSS attacks. Use httpOnly cookies or store tokens in memory.
- Always validate the algorithm: The 'none' algorithm attack allows an attacker to send an unsigned token. Your server must whitelist specific algorithms and reject 'none'.
- Set short expiration times: JWTs cannot be revoked before expiry (without a blacklist). Use short-lived access tokens (15 minutes) with longer-lived refresh tokens.
- Don't put sensitive data in the payload: The payload is Base64-encoded, not encrypted. Anyone can decode it. Never include passwords, credit card numbers, or PII beyond what's needed for authorization.
Inspect any JWT's payload with our JWT Decoder — paste a token to see exactly what data it exposes.
When to Use JWTs
- API authentication — stateless, works across multiple backend services
- Single Sign-On (SSO) — one token works across multiple applications
- Mobile app authentication — no cookie support needed
- Microservices — each service can verify the token independently without shared state
When NOT to use JWTs: Traditional server-rendered apps where sessions work fine, scenarios requiring instant revocation (admin force-logout), or when the payload would be very large.