2 min readUpdated 2026-10-10

Common JWT Security Mistakes Developers Should Avoid

A developer checklist for JWT algorithms, expiry, issuer, audience, signature verification, token storage, and safe debugging.

Maintained by Ali Aygör. Report a correction.

Readable claims are not authenticated claims

A browser decoder can read a JWT header and payload without possessing a trusted verification key. A modified payload can still parse perfectly. Treat everything displayed by a decoder as untrusted until the server verifies the signature and applies its configured token policy.

This site's inspector reports claim checks, not signature validity. A not-expired label only describes the decoded timing value relative to the device clock. It must never be used as a client-side authorization decision.

Test expiry and not-before separately

Use a synthetic fixture with exp in the past and another with nbf in the future. Confirm that the application rejects them according to its verifier policy. NumericDate values use seconds, so a millisecond value can accidentally create a wildly incorrect lifetime.

A missing exp needs a policy decision; it is not automatic proof that a token is valid forever. Define any clock tolerance deliberately rather than repeatedly extending expiry to compensate for an unexplained clock mismatch.

{
  "iss": "https://auth.example.com",
  "aud": ["api", "reports"],
  "nbf": 1700000000,
  "exp": 1700003600
}
// Synthetic claims only; no signature is provided.

Check issuer and audience in the verifier

An audience may be a string or an array of strings. The expected recipient must match the appropriate value. Testing only the string form can reject valid array-based tokens or leave a gap when the application makes assumptions about the representation.

An issuer string in an unverified payload is not proof of identity. Configure trusted issuers and their keys outside the token itself, then test an otherwise plausible token with an unexpected issuer or audience.

Avoid algorithm conclusions based only on a header

An alg=none token is unsigned and needs an explicitly designed trusted use case if it is accepted at all. The server should verify using permitted algorithms and trusted key material. It should not select an arbitrary trust policy from attacker-controlled header text.

HS256 is not inherently broken merely because it uses a shared secret. Its safety depends on a strong secret, appropriate distribution and correct verification. Similarly, an asymmetric algorithm name alone does not prove correct key lookup or signature validation.

Keep real credentials out of debugging artifacts

Prefer synthetic or revoked test tokens when checking a decoder. Active bearer tokens can be replayable credentials even when the claims appear harmless. Redact them from screenshots, tickets and repository fixtures.

Test the server's rejection paths as well as a legitimate token. A decoder is useful for diagnosing representation and claim mismatches; the server's verifier and authorization tests are the evidence that the access decision is correct.

Specifications and references

Continue the investigation

Related tools

Browse all developer tools

Related workflows