API Security3 min read

JWT mistakes we see in real APIs

JSON Web Tokens are easy to adopt and easy to get wrong. These are the common JWT mistakes in APIs, why they matter, and how to fix each one properly.

JSON Web Tokens (JWTs) are everywhere in modern APIs. They are compact, stateless and supported by every major framework. They are also easy to misconfigure, because a token that looks correct can still be accepted for the wrong reasons.

The mistakes below are well documented, and they keep appearing in API testing. Most are not exotic. They come from default settings, copied examples, or validation steps that were assumed rather than checked.

Accepting “alg”: “none”

A JWT header names the algorithm used to sign it. The specification includes none, meaning “unsigned”. Some libraries, or custom verification code, will accept an unsigned token if the header asks for it.

An attacker can then change any claim, such as the user ID or role, strip the signature, and set alg to none.

Fix: configure the verifier with the exact algorithm you expect, for example RS256, and reject everything else. Never let the token’s own header decide how it is verified.

Weak secrets for HS256

HMAC algorithms such as HS256 use a shared secret. If that secret is short, guessable or copied from documentation, an attacker who has one valid token can try candidate secrets offline until one produces a matching signature. Once they have it, they can mint any token they like.

Fix: use a long, randomly generated secret stored in a secrets manager, or switch to an asymmetric algorithm so that services which only verify tokens never hold the signing key.

Missing or incomplete claim validation

Checking the signature is only half the job. A correctly signed token can still be invalid for your API.

Common gaps include:

  • No exp check, so tokens never expire.
  • No aud (audience) check, so a token issued for one service is accepted by another.
  • No iss (issuer) check, so tokens from an unexpected issuer are trusted.
  • Very long lifetimes, which turn a leaked token into long-term access.

Fix: validate exp, nbf, iss and aud on every request, and keep access-token lifetimes short. Use refresh tokens, stored more carefully, for longer sessions.

Trusting key locations from the token

Some header fields tell the verifier where to find the key: jku (a URL to a key set), x5u (a certificate URL) and jwk (an embedded key). If the server follows these blindly, an attacker can point it at a key they control.

The kid (key ID) field has a related risk. If its value is used in a file path or database query without validation, it can become an injection point.

Fix: ignore jku, x5u and jwk unless you have a strict allow-list. Treat kid as untrusted input and look it up only in a fixed set of known keys.

Sensitive data in claims

Because payloads are readable, putting personal data, internal IDs or secrets into a JWT exposes them to anyone who sees the token. That includes browser extensions, logs, proxies and error-reporting tools.

Fix: keep claims to what the API needs to authorize the request. Look up anything sensitive on the server.

Tokens in URLs

Passing a token as a query parameter, for example ?token=eyJ…, is convenient for links and downloads. It also writes the token into browser history, server logs, proxy logs and Referer headers sent to other sites.

Fix: send tokens in the Authorization header. For download links, use short-lived, single-purpose tokens that cannot be used for anything else.

No way to revoke tokens

Stateless tokens cannot easily be “logged out”. If an account is compromised or a user’s role changes, an old token may stay valid until it expires.

Fix: keep lifetimes short, rotate signing keys when needed, and keep a small revocation list or token version for high-risk events such as password changes.

How to check your own tokens

Start with a token from a test environment. Our free JWT Decoder & Inspector decodes it entirely in your browser and flags several of the issues above, such as alg: none, missing expiry, long lifetimes and key-location headers. Never paste a production token into any online tool.

A decoder can only see the token itself. Whether your API actually validates it correctly needs testing against the API, which is part of every API penetration test.

Want to know how your API handles forged and expired tokens? Get in touch.

One practical security note a week.

No spam. Unsubscribe any time.

Need a pentest for an audit, a customer, or peace of mind?

Tell us what you need tested. You’ll get a fixed-fee proposal with tester-days and timeline stated, usually within a few days of the scoping call.