What is a JSON Web Token?
A JSON Web Token (JWT) is a compact, URL-safe way to represent claims between two parties. It is widely used for authentication and authorization in web applications and APIs. When a user logs in, the server creates a JWT and sends it to the client. The client then includes this token in subsequent requests to prove its identity.
JWT is defined in RFC 7519 and has become the de facto standard for stateless authentication in REST APIs, microservices, and single-page applications.
The Structure of a JWT
A JWT consists of three parts separated by dots (.):
xxxxx.yyyyy.zzzzz Header.Payload.Signature1. Header
The header typically contains two fields: the token type (typ) and the signing algorithm (alg). It is Base64URL encoded.
{
"alg": "HS256",
"typ": "JWT"
}2. Payload
The payload contains claims — statements about the user and additional metadata. There are three types of claims:
- Registered claims: Predefined fields like
iss(issuer),exp(expiration),sub(subject),aud(audience) - Public claims: Custom fields you define, like
name,email,role - Private claims: Custom claims agreed upon between parties
{
"sub": "1234567890",
"name": "John Doe",
"email": "[email protected]",
"role": "admin",
"iat": 1516239022,
"exp": 1516325422
}3. Signature
The signature verifies that the token has not been tampered with. It is created by combining the encoded header, encoded payload, and a secret key:
HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret )💡 Important: The payload is only Base64URL encoded, not encrypted. Anyone can decode and read the payload. Never store sensitive data like passwords in a JWT unless you use JWE (JSON Web Encryption).
Common JWT Claims Explained
| Claim | Name | Description |
|---|---|---|
iss | Issuer | Who issued the token (e.g. your auth server) |
sub | Subject | Who the token is about (usually user ID) |
aud | Audience | Who the token is intended for |
exp | Expiration | Unix timestamp when token expires |
iat | Issued At | Unix timestamp when token was issued |
nbf | Not Before | Token is invalid before this timestamp |
jti | JWT ID | Unique identifier to prevent replay attacks |
JWT Signing Algorithms
JWTs can be signed using symmetric or asymmetric algorithms:
| Algorithm | Type | Use Case |
|---|---|---|
| HS256, HS384, HS512 | Symmetric (HMAC) | Single server, shared secret |
| RS256, RS384, RS512 | Asymmetric (RSA) | Multiple services, public key verification |
| ES256, ES384, ES512 | Asymmetric (ECDSA) | High performance, smaller keys |
How JWT Authentication Works
The typical JWT authentication flow looks like this:
- User submits username and password to the login endpoint
- Server validates credentials, creates a JWT signed with a secret key
- Server returns the JWT to the client
- Client stores the JWT (typically in memory or localStorage)
- Client includes the JWT in the
Authorizationheader for protected requests:Authorization: Bearer <token> - Server validates the JWT signature and checks expiration before processing the request
JWT Security Best Practices
- Always set an expiration (
exp) — short-lived tokens (15 minutes to 1 hour) reduce risk - Use HTTPS — never transmit JWTs over unencrypted connections
- Store tokens securely — prefer memory storage over localStorage to prevent XSS attacks
- Use RS256 over HS256 for multi-service architectures — no need to share secret keys
- Validate all claims — check
iss,aud, andexpon every request - Implement token revocation with a refresh token pattern for sensitive applications
⚠️ The "alg: none" attack: Always explicitly specify which algorithms are valid on your server. Never accept tokens with alg: none as this bypasses signature verification entirely.
JWT vs Session Tokens
| JWT | Session Token | |
|---|---|---|
| Storage | Client-side | Server-side |
| Scalability | Excellent (stateless) | Requires session store |
| Revocation | Difficult (until expiry) | Instant |
| Size | Larger (100-500 bytes) | Tiny (32-128 bytes) |
| Best for | APIs, microservices | Traditional web apps |