JWT Tokens Explained: Authentication for Modern Web Apps
· 6 min read
JSON Web Tokens (JWT) have become the de facto standard for authentication in modern web applications. They provide a compact, URL-safe way to represent claims between two parties, enabling stateless authentication that scales horizontally without shared session storage. This guide explains how JWTs work, their structure, security considerations, and best practices for production use.
What Is JWT?
JWT (pronounced "jot") is an open standard (RFC 7519) that defines a compact, self-contained format for securely transmitting information between parties as a JSON object. The information is digitally signed using a secret (HMAC) or a public/private key pair (RSA or ECDSA), ensuring the token's integrity and authenticity.
JWTs are commonly used for:
- Authentication: After login, the server issues a JWT that the client includes with subsequent requests
- Authorization: JWTs can carry user roles and permissions, allowing servers to make access control decisions
- Information exchange: The signed nature of JWTs ensures the sender is who they claim and the data has not been tampered with
🛠️ Decode and inspect JWTs
JWT Structure
A JWT consists of three parts separated by dots: header.payload.signature
Header
The header typically contains two fields:
{
"alg": "HS256",
"typ": "JWT"
}
alg specifies the signing algorithm (HS256, RS256, ES256, etc.) and typ declares the token type. This JSON is Base64Url-encoded to form the first part of the JWT.
Payload
The payload contains claims — statements about the user and additional metadata:
{
"sub": "1234567890",
"name": "Jane Developer",
"email": "[email protected]",
"role": "admin",
"iat": 1710590400,
"exp": 1710676800
}
There are three types of claims:
- Registered claims: Standard fields like
iss(issuer),sub(subject),aud(audience),exp(expiration),iat(issued at),nbf(not before),jti(JWT ID) - Public claims: Custom claims registered in the IANA JSON Web Token Claims registry to avoid collisions
- Private claims: Custom claims agreed upon between parties (e.g.,
role,permissions)
Signature
The signature is created by combining the encoded header, encoded payload, and a secret:
HMACSHA256(
base64UrlEncode(header) + "." + base64UrlEncode(payload),
secret
)
The signature verifies the token was not altered in transit. For RS256, the server signs with a private key and verifies with the corresponding public key, enabling verification without sharing the signing secret.
How JWT Authentication Works
The typical JWT authentication flow follows these steps:
- Login: User submits credentials (username/password) to the authentication endpoint
- Token generation: Server validates credentials, creates a JWT with user claims, signs it, and returns it to the client
- Token storage: Client stores the JWT (typically in memory or an httpOnly cookie)
- Authenticated requests: Client includes the JWT in the Authorization header:
Authorization: Bearer <token> - Token verification: Server verifies the signature, checks expiration, and extracts user information from the payload
- Response: If valid, the server processes the request; if invalid or expired, returns 401 Unauthorized
Refresh Token Pattern
Access tokens should be short-lived (5-15 minutes). Use a refresh token pattern for better security:
- Issue a short-lived access token (JWT) and a long-lived refresh token
- Store the refresh token in an httpOnly, secure, SameSite cookie
- When the access token expires, use the refresh token to obtain a new access token
- Rotate refresh tokens on each use (one-time use)
- Maintain a server-side allowlist or blocklist for refresh tokens to enable revocation
Security Best Practices
- Use strong secrets: For HMAC algorithms, use at least 256-bit random secrets. Never use predictable values
- Set expiration: Always include the
expclaim. Keep access tokens short-lived (5-15 minutes) - Validate all claims: Check
iss,aud,exp, andnbfon every request - Use appropriate algorithms: RS256 or ES256 for distributed systems; HS256 only when the signing and verifying party is the same
- Never store sensitive data in the payload: JWTs are encoded, not encrypted. Anyone can decode and read the payload
- Use HTTPS only: Never transmit JWTs over unencrypted connections
- Implement token revocation: Maintain a blocklist of revoked tokens for critical operations like password changes or user deactivation
Use our JWT Decoder to inspect tokens during development and debugging. Document your API authentication with our Markdown Editor.
Common Vulnerabilities
Algorithm None Attack
Some JWT libraries accept tokens with "alg": "none", which means no signature verification. Always validate the algorithm server-side and reject tokens with unexpected algorithms.
Algorithm Confusion
An attacker changes the algorithm from RS256 to HS256 and signs with the public key (which is often publicly available). The server, expecting HS256, uses the public key as the HMAC secret and validates the forged token. Mitigation: explicitly specify expected algorithms in your verification code.
Weak Secrets
HMAC-signed JWTs with weak secrets can be cracked by brute force. Tools like hashcat can try millions of secrets per second. Use cryptographically random secrets of at least 256 bits.
Token Leakage
JWTs stored in localStorage are vulnerable to XSS attacks. JWTs in URLs can be leaked through referrer headers or server logs. Prefer httpOnly cookies with the Secure and SameSite flags for token storage in browser applications.
Missing Expiration
Tokens without expiration remain valid indefinitely. If compromised, they provide permanent access. Always set the exp claim and implement token refresh mechanisms.
Key Takeaways
- JWTs consist of three Base64Url-encoded parts: header, payload, and signature
- Use short expiration times for access tokens and implement refresh token rotation
- Validate algorithms, claims, and signatures on every request
- Never store sensitive data in JWT payloads — they are encoded, not encrypted
- Protect against algorithm confusion, weak secrets, and token leakage vulnerabilities
Related Tools
Frequently Asked Questions
What is the difference between JWT and session-based authentication?
Session-based authentication stores session data on the server and sends a session ID cookie to the client. JWT authentication stores all necessary data in the token itself (stateless), eliminating the need for server-side session storage. JWTs scale better in distributed systems but are harder to revoke.
Can JWTs be revoked?
JWTs are stateless by design, so they cannot be directly revoked. However, you can implement revocation through short expiration times combined with refresh tokens, or by maintaining a server-side blocklist of revoked token IDs (jti). The trade-off is adding state back to a stateless system.
Where should I store JWTs in a browser application?
The most secure option is an httpOnly cookie with Secure and SameSite=Strict flags. This protects against XSS attacks since JavaScript cannot access httpOnly cookies. Avoid localStorage (vulnerable to XSS) and URL parameters (leaked via referrer headers). For SPAs, in-memory storage combined with refresh token cookies is another secure approach.
What is the difference between HS256 and RS256?
HS256 (HMAC with SHA-256) uses a single shared secret for both signing and verification. RS256 (RSA with SHA-256) uses a private key for signing and a public key for verification. RS256 is preferred for distributed systems where multiple services need to verify tokens without knowing the signing secret.
How long should a JWT access token last?
Access tokens should typically expire in 5 to 15 minutes. This limits the damage window if a token is compromised. Use refresh tokens (with longer expiration, e.g., 7-30 days) to obtain new access tokens without requiring re-authentication. Always rotate refresh tokens on each use.