JWT Security Best Practices for Developers
JWTs are convenient, compact, and widely used in modern authentication. They are also easy to misuse.
The most important rule is simple: decoding a JWT is not the same as trusting it. A decoded payload only tells you what the token says. Verification tells you whether the token should be accepted.
Use the JWT Decoder to inspect tokens while debugging, then rely on your server-side authentication library for trust decisions.
1. Always Verify the Signature
A JWT has three sections:
header.payload.signatureThe header and payload are encoded, not encrypted. Anyone can read them. Anyone can also create a fake token.
The signature is what lets your server detect tampering. If your application accepts a JWT without verifying the signature, an attacker may be able to change claims such as sub, role, or admin.
Decoding vs Verification
| Action | What it tells you | Can you trust the token? |
|---|---|---|
| Decode header | Algorithm and token type | No |
| Decode payload | Claims the token contains | No |
| Check expiration | Whether exp is in the future | Not by itself |
| Verify signature | Whether the token was signed by the expected key | Necessary |
| Validate issuer/audience | Whether the token belongs to this system | Necessary |
Decoding is useful for debugging. Verification and claim validation are required for authorization decisions.
2. Reject Weak or Unexpected Algorithms
The JWT header includes an alg field.
Examples:
{
"alg": "RS256",
"typ": "JWT"
}Your application should not blindly trust whatever algorithm appears in the header. Configure allowed algorithms explicitly.
Avoid:
- Accepting
none - Allowing unexpected algorithm changes
- Mixing symmetric and asymmetric verification incorrectly
- Using weak shared secrets with HMAC algorithms
For production systems, choose mature authentication libraries and configure accepted algorithms explicitly. Do not write your own JWT verification logic unless you are building security infrastructure and have expert review.
3. Keep Expiration Short
JWTs often include these time-based claims:
| Claim | Meaning |
|---|---|
exp | Expiration time |
iat | Issued-at time |
nbf | Not valid before |
Access tokens should usually be short-lived. Many systems use minutes, not days.
Long-lived tokens increase the damage if a token is copied from logs, browser storage, or a compromised device.
Use the Timestamp Converter to inspect Unix timestamp claims while debugging.
Access Tokens vs Refresh Tokens
Many systems use two token types:
- access tokens for API requests
- refresh tokens for obtaining new access tokens
Access tokens are usually short-lived. Refresh tokens are more sensitive because they can extend a session. Store, rotate, and revoke refresh tokens with extra care.
Do not put a long-lived refresh token anywhere it may be copied into logs, frontend error reports, browser screenshots, or analytics payloads.
4. Do Not Put Secrets in the Payload
JWT payloads are readable by design.
Avoid storing:
- Passwords
- API keys
- Private user notes
- Payment data
- Long-lived credentials
- Sensitive internal authorization rules
It is usually fine to include identifiers and basic claims such as sub, iss, aud, exp, and a small set of roles or scopes.
5. Validate Issuer and Audience
A valid signature is necessary but not always enough.
Your application should also validate:
iss: did the expected issuer create this token?aud: was the token intended for this application or API?exp: has it expired?nbf: is it valid yet?sub: does the subject map to a real account or service?
Skipping issuer or audience checks can let a token from one system be accepted by another.
Validate Scopes and Roles Server-Side
Roles and scopes in a JWT are only useful after the token is verified. Once verified, your API still needs to check whether the claim permits the specific action.
For example:
scope: "read:reports"should not automatically allow:
delete:reportsKeep authorization checks close to the protected resource. A valid token proves identity or session context; it does not automatically prove every permission.
6. Choose Storage Carefully
There is no perfect browser storage location for all applications.
Common choices:
HttpOnlycookies reduce direct JavaScript access but need CSRF protection.localStorageis easy to use but exposed to XSS.- In-memory storage limits persistence but requires refresh flows.
For sensitive applications, prefer architecture-level guidance from your authentication framework and security team.
Key Rotation and Revocation
JWTs are often stateless, which makes them efficient but harder to revoke instantly. If a token is valid until exp, the server may continue accepting it unless you add a revocation strategy.
Common approaches include:
- short access token lifetimes
- refresh token rotation
- server-side blocklists for high-risk events
- key rotation with
kidheader support - forcing reauthentication after password or role changes
Key rotation is especially important for long-running systems. If signing keys never change, a leaked key can remain dangerous for a long time.
7. Avoid Logging Live Tokens
Tokens often appear in:
- Authorization headers
- Debug logs
- Browser console output
- Error tracking payloads
- API gateway logs
Mask or remove live tokens before sharing screenshots, tickets, or logs.
Common JWT Mistakes
Treating Base64 as encryption JWT header and payload sections are usually Base64URL-encoded. They are not hidden.
Trusting frontend claims The browser can decode a token for display, but the server must make authorization decisions.
Using oversized payloads Large tokens increase request size and may leak unnecessary user or authorization details.
Ignoring clock skew Small time differences between systems can affect exp and nbf. Libraries often support a small allowed skew.
Forgetting logout behavior If access tokens are long-lived, “logout” may only remove the token from the client, not invalidate copies elsewhere.
Safe Debugging Workflow
- Decode the token locally.
- Inspect
alg,typ,exp,iss,aud, andsub. - Confirm the payload does not contain secrets.
- Verify the signature in trusted server-side code.
- Remove the token from logs and screenshots.
Related QuickToolFlow Tools
- JWT Decoder for inspecting token headers, payloads, and claims.
- Base64 Encoder and Decoder for understanding JWT section encoding.
- Timestamp Converter for reading
exp,iat, andnbfvalues.
Related Guides
- JWT Decoder Guide for the structure of JWT headers, payloads, and signatures.
- Base64 vs URL Encoding for Base64Url behavior in tokens.
- Security & Encoding Tools for JWT, hashing, password, and encoding utilities.
Keep going