JWT Tokens Decoded
What Is a JWT?
A JSON Web Token (JWT, pronounced “jot”) is a compact, URL-safe token format used to securely transmit information between parties. JWTs are widely used for authentication and authorization in modern web applications. When you log into a website and remain authenticated across page loads, there is a good chance a JWT is working behind the scenes.
JWTs are self-contained, meaning they carry all the information needed to verify the token’s authenticity and extract user data without querying a database. This property makes them particularly valuable in distributed systems and microservice architectures.
JWT Structure
Every JWT consists of three parts separated by dots:
Header.Payload.Signature
Each part is Base64URL-encoded, making the token safe for use in URLs, HTTP headers, and HTML attributes.
Header: Contains metadata about the token, primarily the signing algorithm and token type:
{
"alg": "HS256",
"typ": "JWT"
}
Payload: Contains the claims, which are statements about the user and additional data:
{
"sub": "1234567890",
"name": "Jane Doe",
"iat": 1516239022,
"exp": 1516242622
}
Signature: Created by taking the encoded header and payload, combining them with a secret key, and applying the specified algorithm. The signature verifies that the token has not been tampered with.
Standard Claims
The JWT specification defines several registered claims (all optional but recommended):
- iss (Issuer): Who created the token
- sub (Subject): Who the token is about, typically a user ID
- aud (Audience): Who the token is intended for
- exp (Expiration Time): When the token expires (Unix timestamp)
- nbf (Not Before): When the token becomes valid
- iat (Issued At): When the token was created
- jti (JWT ID): A unique identifier for the token, useful for preventing replay attacks
You can also add custom claims for application-specific data like user roles, permissions, or preferences. Keep custom claims minimal to keep the token size small.
Signing Algorithms
JWTs can be signed using two categories of algorithms:
Symmetric algorithms (like HS256) use the same secret key for both signing and verification. This works well when the same server creates and validates tokens. The secret must be kept confidential on the server.
Asymmetric algorithms (like RS256 or ES256) use a private key for signing and a public key for verification. This is ideal for distributed systems where multiple services need to verify tokens but only one service should create them. The public key can be shared freely.
Common choices:
- HS256: HMAC with SHA-256. Simple, fast, good for single-server applications.
- RS256: RSA with SHA-256. Better for microservices. Public key can be published for any service to verify.
- ES256: ECDSA with SHA-256. Shorter keys than RSA with equivalent security. Increasingly popular.
JWT Authentication Flow
A typical JWT authentication flow works like this:
- The user sends their credentials (username and password) to the authentication server.
- The server verifies the credentials against the database.
- If valid, the server creates a JWT containing user claims and signs it with a secret key.
- The server sends the JWT back to the client.
- The client stores the JWT (typically in memory or an HTTP-only cookie).
- For subsequent requests, the client sends the JWT in the Authorization header.
- The server verifies the signature, checks expiration, and extracts user information from the claims.
This flow eliminates the need for the server to maintain session state, making it ideal for stateless APIs and horizontally scaled systems.
Security Best Practices
JWT security requires careful implementation:
- Always verify the signature: Never trust a JWT without verifying its signature. A JWT decoder can inspect token contents, but production systems must cryptographically verify.
- Set short expiration times: Access tokens should expire in minutes, not hours or days. Use refresh tokens for longer sessions.
- Use HTTPS: JWTs transmitted over unencrypted connections can be intercepted. Always use HTTPS.
- Validate all claims: Check
exp,iss,aud, and any other relevant claims on every request. - Store tokens securely: Prefer HTTP-only cookies over localStorage to prevent XSS attacks from accessing tokens.
- Never store sensitive data in the payload: The payload is encoded, not encrypted. Anyone with the token can decode and read the claims.
- Use strong secrets: For symmetric algorithms, use randomly generated secrets of at least 256 bits. Never use predictable strings.
Common JWT Mistakes
These errors create security vulnerabilities:
- Using the “none” algorithm: Some libraries accept tokens with
"alg": "none"and no signature. Always validate that the algorithm matches your expectations. - Confusing encoding with encryption: Base64 encoding is reversible by anyone. JWTs are signed (tamper-evident) but not encrypted (not confidential). If you need encrypted tokens, use JWE (JSON Web Encryption).
- Not checking expiration: Accepting expired tokens defeats the purpose of having an expiration claim.
- Storing JWTs in localStorage: Vulnerable to XSS attacks. HTTP-only cookies are safer because JavaScript cannot access them.
- Making tokens too large: JWTs are sent with every request. Stuffing them with unnecessary data increases bandwidth usage and can exceed header size limits.
JWT vs Session-Based Authentication
Both approaches have trade-offs:
JWTs are stateless, scale horizontally without shared session storage, and work well across domains. However, they cannot be individually revoked without additional infrastructure (like a token blacklist), and they increase request size.
Sessions are stored server-side, can be instantly revoked, and keep request sizes small (only a session ID is transmitted). However, they require shared storage in multi-server environments and create a server-side state dependency.
Many production systems use a hybrid approach: JWTs for short-lived access tokens and server-side sessions for refresh tokens that can be revoked.
Debugging JWTs
When troubleshooting JWT-related issues, being able to decode a token and inspect its claims is essential. Check the expiration time, verify the issuer and audience match your expectations, and confirm the algorithm is correct. A JWT decoder lets you paste a token and instantly see the decoded header and payload.
For development and testing, being able to quickly decode tokens without writing code speeds up debugging significantly.
Try our free JWT Decoder — no signup required.
Explore all free tools on CalcHub
Browse Tools