JSON Web Token (JWT) is an open standard (RFC 7519) for securely transmitting information between parties as a JSON object. JWT is widely used for authentication and authorization in modern web applications and APIs. In this article, we'll explore how JWT tokens work, their structure, and best practices for secure implementation.
What Is JWT?
JWT (pronounced "jot") is a compact, URL-safe means of representing claims between two parties. A token consists of three parts separated by dots: Header.Payload.Signature. Each part is Base64URL encoded.
Unlike traditional sessions where the server stores user state, JWT is stateless β all necessary information is contained within the token itself. This makes JWT ideal for distributed systems and microservice architectures.
JWT Token Structure
Header
The header typically contains two fields: the token type (typ) and the signing algorithm (alg). The most common algorithms are HS256 (HMAC with SHA-256) and RS256 (RSA with SHA-256).
Example header:
{
"alg": "HS256",
"typ": "JWT"
}
Payload
The payload contains claims β statements about the user and additional metadata. There are three types of claims:
- Registered claims β standard fields:
iss(issuer),exp(expiration),sub(subject),aud(audience),iat(issued at) - Public claims β defined in the IANA registry or using URIs to avoid collisions
- Private claims β custom fields agreed upon by parties (e.g.,
user_id,role)
Example payload:
{
"sub": "1234567890",
"name": "John Doe",
"role": "admin",
"iat": 1516239022,
"exp": 1516242622
}
Signature
The signature is created by encoding the Header and Payload in Base64URL, joining them with a dot, and signing with a secret key. The signature ensures the token hasn't been tampered with after creation.
For HS256, the formula is:
HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)
How JWT Authentication Works
The authentication flow with JWT typically follows these steps:
- Login: The user sends credentials (email + password) to the server
- Token generation: The server validates credentials and creates a JWT with appropriate claims
- Storage: The client stores the token (usually in localStorage or httpOnly cookie)
- Requests: For each request, the client includes the token in the
Authorization: Bearer <token>header - Verification: The server verifies the token signature and extracts user data from the payload
Advantages of JWT
- Stateless: The server doesn't need to store sessions in a database or memory
- Scalability: Perfect for microservices β any service can verify the token independently
- Cross-domain: JWT works seamlessly across different domains and services
- Compact: Small size allows transmission via URL, POST parameters, or headers
- Self-contained: All authorization information is embedded within the token
JWT Security Best Practices
1. Always Set Expiration
Never create tokens without an exp claim. The recommended access token lifetime is 15 minutes to 1 hour. For longer sessions, use refresh tokens that can issue new access tokens.
2. Use httpOnly Cookies
Instead of localStorage, store JWT in httpOnly cookies that are inaccessible to JavaScript. This protects against XSS attacks. Additionally, set the Secure and SameSite flags.
3. Never Store Sensitive Data in Payload
The payload is only Base64 encoded, not encrypted. Anyone can decode it. Never include passwords, credit card numbers, or other sensitive information in the token payload.
4. Use Strong Algorithms
Avoid the none algorithm entirely. For symmetric signing, use HS256 with a long secret (minimum 256 bits). For asymmetric operations, prefer RS256 or ES256.
5. Validate All Claims
When verifying a token, always check: exp (not expired), iss (correct issuer), aud (correct audience). Don't trust a token just because it has a valid signature.
6. Implement Token Revocation
Although JWT is stateless, sometimes you need to revoke tokens (e.g., on logout or password change). Use a token blacklist or short-lived access tokens with refresh token rotation.
Common JWT Mistakes
- Skipping signature verification β the most dangerous mistake that allows token forgery
- Using weak secrets β short or predictable secrets can be brute-forced
- Storing in localStorage β vulnerable to XSS attacks
- Excessively long expiration β increases the attack window if a token is compromised
- Transmitting via URL β tokens may end up in server logs and browser history
JWT vs Sessions: When to Use Each
JWT is best suited for:
- Single-page applications (SPA) with separate APIs
- Microservice architectures
- Mobile applications
- Single sign-on (SSO) systems
Traditional sessions work better for:
- Server-rendered web applications (Laravel, Rails, Django)
- Applications requiring immediate access revocation
- Simple projects without complex architectures
Practice: Decoding JWT
Want to see what's inside a JWT token? Use our JWT debugger tool β it breaks down the token into its components, displays the Header, Payload, and verifies the signature. It's an invaluable tool for developers debugging authentication flows.
Conclusion
JWT tokens are a powerful authentication mechanism for modern applications. They provide stateless authorization, scale easily, and work across different services. The key is following security best practices: setting expiration times, using strong algorithms, storing tokens securely, and validating all claims. When implemented correctly, JWT significantly simplifies architecture and improves application performance.