JWT Tokens Explained: How JSON Web Tokens Actually Work
JWTs are everywhere in modern web development — API authentication, SSO, microservices. Yet most developers use them without truly understanding how they work or the security pitfalls. Let's fix that.
What Is a JWT?
A JSON Web Token (JWT) is a compact, URL-safe token format defined by RFC 7519. It encodes a set of claims as a JSON object and optionally signs or encrypts that payload. JWTs are primarily used for authentication and authorization in web applications and APIs.
A JWT looks like this:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4iLCJpYXQiOjE3MTExMjAwMDB9.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
Those three Base64-encoded segments separated by dots are the header, payload, and signature. You can paste any JWT into our JWT Decoder to inspect its contents instantly.
The Three Parts of a JWT
1. Header
The header is a JSON object specifying the token type and signing algorithm:
{
"alg": "HS256",
"typ": "JWT"
}
Common algorithms include HS256 (HMAC-SHA256, symmetric), RS256 (RSA-SHA256, asymmetric), and ES256 (ECDSA-SHA256, asymmetric). The choice matters significantly for security.
2. Payload (Claims)
The payload contains claims — statements about the user and metadata. There are three types:
- Registered claims: Predefined fields like
iss(issuer),sub(subject),exp(expiration),iat(issued at),aud(audience),nbf(not before),jti(JWT ID). - Public claims: Custom claims registered in the IANA JWT Claims Registry to avoid collisions.
- Private claims: Custom claims agreed upon between producer and consumer, like
user_id,role, orpermissions.
{
"sub": "user_12345",
"name": "Jane Developer",
"role": "admin",
"iat": 1711120000,
"exp": 1711206400
}
JWTs are signed, not encrypted by default. Anyone can decode the payload using a Base64 decoder or our JWT Decoder. Never put sensitive data (passwords, secrets, PII) in a JWT payload unless you use JWE (JSON Web Encryption).
3. Signature
The signature ensures the token has not been tampered with. For HS256, it is computed as:
HMACSHA256(
base64UrlEncode(header) + "." + base64UrlEncode(payload),
secret
)
The server verifies the signature using the same secret (HS256) or the corresponding public key (RS256/ES256). If anyone modifies the header or payload, the signature check fails.
HS256 vs RS256: Which Should You Use?
HS256 (HMAC + SHA-256) uses a single shared secret for both signing and verification. It is simple and fast, but requires every service that verifies tokens to have the secret. If any service is compromised, the attacker can forge tokens.
RS256 (RSA + SHA-256) uses an asymmetric key pair. Only the authentication server has the private key to sign tokens. Any service can verify using the public key. This is more secure for distributed systems because public keys can be shared freely.
- Use HS256 for simple applications where only one server signs and verifies tokens.
- Use RS256/ES256 for microservices, third-party integrations, or any system where multiple services need to verify tokens independently.
How JWT Authentication Works in Practice
- Login: User sends credentials (email + password) to the auth endpoint.
- Token generation: Server verifies credentials, creates a JWT with user claims, signs it, and returns it.
- Client storage: The client stores the JWT (typically in memory or an httpOnly cookie).
- API requests: The client sends the JWT in the
Authorization: Bearer <token>header with every request. - Verification: The API server verifies the signature, checks expiration, and extracts claims to authorize the request.
Token Refresh Strategy
Short-lived access tokens (5-15 minutes) minimize the damage window if a token is stolen. But users should not have to log in every 15 minutes. The solution is a refresh token:
- The access token is a short-lived JWT sent with every API request.
- The refresh token is a long-lived opaque token stored in an httpOnly cookie. It is sent only to the
/refreshendpoint. - When the access token expires, the client silently exchanges the refresh token for a new access token.
- Refresh tokens can be revoked server-side (stored in a database), giving you a logout mechanism.
Common JWT Security Mistakes
1. The "alg: none" Attack
Some JWT libraries accept tokens with "alg": "none", meaning no signature verification. An attacker can forge any claims. Always validate the algorithm and reject none.
2. Algorithm Confusion (RS256 → HS256)
If a server is configured for RS256 but a library also accepts HS256, an attacker can sign a forged token using the public key as the HS256 secret. Always explicitly specify allowed algorithms in your verification code.
3. Not Validating Expiration
Always check the exp claim. A JWT without expiration is valid forever if the signing key is never rotated. Use our timestamp converter to inspect Unix timestamps in JWT claims.
4. Storing JWTs in localStorage
localStorage is accessible to any JavaScript on the page, making it vulnerable to XSS attacks. Prefer httpOnly cookies with SameSite=Strict and Secure flags, or store tokens in memory with a refresh token in a cookie.
5. Putting Sensitive Data in the Payload
JWTs are Base64-encoded, not encrypted. Anyone can decode them. Never include passwords, API keys, or sensitive personal data. If you need encrypted tokens, use JWE or encrypt specific claims.
Decode and Inspect JWTs Instantly
Paste any JWT to see its header, payload, and signature. Verify expiration, check claims, and debug auth issues. 100% client-side.
Open JWT DecoderJWT Best Practices for 2026
- Keep tokens short-lived (5-15 min for access tokens) and use refresh tokens for session continuity.
- Use asymmetric algorithms (RS256, ES256) for distributed systems. ECDSA (ES256) is faster and produces smaller signatures than RSA.
- Validate everything: algorithm, expiration, issuer, audience. Do not just verify the signature.
- Rotate signing keys regularly and support key ID (
kid) in the header for smooth rotation. - Use JWKS (JSON Web Key Sets) endpoints for public key distribution, especially with OAuth2/OIDC providers.
- Implement token revocation via a deny list or short expiration + refresh tokens.
- Minimize payload size — include only essential claims. Large JWTs increase bandwidth on every request.
- Never log full JWTs in server logs. Use the hash generator to create a fingerprint for logging instead.
The Bottom Line
JWTs are powerful but easy to misuse. Understand the structure, choose the right algorithm, validate rigorously, and store tokens securely. When in doubt, decode and inspect your tokens with our JWT Decoder to verify they contain exactly what you expect.
Explore more developer tools: Base64 encoder, JSON Formatter, Hash Generator, and 50+ more — all free and running entirely in your browser.