Security

JWT Security Best Practices for Developers

· QuickToolFlow
jwt authentication api security tokens web security

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.signature

The 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

ActionWhat it tells youCan you trust the token?
Decode headerAlgorithm and token typeNo
Decode payloadClaims the token containsNo
Check expirationWhether exp is in the futureNot by itself
Verify signatureWhether the token was signed by the expected keyNecessary
Validate issuer/audienceWhether the token belongs to this systemNecessary

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:

ClaimMeaning
expExpiration time
iatIssued-at time
nbfNot 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:reports

Keep 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:

  • HttpOnly cookies reduce direct JavaScript access but need CSRF protection.
  • localStorage is 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 kid header 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

  1. Decode the token locally.
  2. Inspect alg, typ, exp, iss, aud, and sub.
  3. Confirm the payload does not contain secrets.
  4. Verify the signature in trusted server-side code.
  5. Remove the token from logs and screenshots.

Keep going

Related tools and guides

All tools