I’ve been using JWTs for a while, but I’m just now understanding how they actually work under the hood.
JWT Structure
A JWT has three parts separated by dots:
header.payload.signature
Header: Algorithm and token type
{
"alg": "HS256",
"typ": "JWT"
}
Payload: Data (claims)
{
"userId": "123",
"email": "user@example.com",
"exp": 1234567890
}
Signature: Verifies the token hasn’t been tampered with
How Signing Works
const signature = HMACSHA256(
base64UrlEncode(header) + "." + base64UrlEncode(payload),
secret
);
The signature proves the token was created by someone with the secret key.
Important: JWTs Are NOT Encrypted
The payload is base64-encoded, not encrypted. Anyone can decode and read it:
const payload = JSON.parse(atob(token.split('.')[1]));
Never put sensitive data in JWTs!
What I’m Learning
Expiration: Always set an expiration time
jwt.sign(payload, secret, { expiresIn: '7d' });
Refresh tokens: Long-lived tokens for getting new access tokens.
Token storage: Where to store tokens (localStorage vs cookies).
Revocation: JWTs can’t be revoked easily (they’re stateless).
Security Considerations
Use HTTPS: Tokens can be intercepted over HTTP.
Short expiration: Limit damage if token is stolen.
Secure secret: Use a strong, random secret key.
Validate everything: Always verify the signature.
Common Mistakes
Storing sensitive data: JWTs are readable by anyone.
No expiration: Tokens should expire.
Weak secrets: Use strong, random secrets.
Not validating: Always verify tokens on the server.
Current Understanding
JWTs are useful for stateless authentication, but they’re not perfect. Understanding how they work helps me use them securely.