◇ Web Security

JSON Web Tokens (JWT): Security Best Practices

JSON Web Tokens, or JWTs, are a compact, self-contained format for transmitting signed claims between parties. They are widely used for authentication and authorization because a server can verify a token's integrity without a database lookup, enabling stateless sessions and clean service-to-service communication. That convenience comes with sharp edges, and several well-known JWT vulnerabilities stem from validating tokens incorrectly.

Anatomy of a JWT

A JWT consists of three base64url-encoded parts separated by dots: a header, a payload, and a signature.

eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9   header:  {"alg":"RS256","typ":"JWT"}
eyJzdWIiOiIxMjMiLCJleHAiOjE3MH0        payload: {"sub":"123","exp":1700000000}
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV     signature over header.payload

The header names the signing algorithm. The payload carries claims, such as the subject, expiration time, issuer, and audience. The signature is computed over the header and payload using either a shared secret (HMAC algorithms such as HS256) or a private key (asymmetric algorithms such as RS256). The three parts are joined with dots into a single compact string that travels comfortably in an HTTP header, which is part of why the format is popular for APIs. Anyone can read the payload, since it is only encoded, not encrypted, so a JWT must never carry secrets in plaintext.

Common JWT Vulnerabilities

The alg None Attack

Some libraries have honored an alg value of none, meaning the token is unsigned. If a server accepts such a token, an attacker can forge arbitrary claims. Always reject tokens whose algorithm is not one you explicitly expect.

Algorithm Confusion

In this attack, a server that verifies RS256 tokens is tricked into treating the token as HS256. The attacker signs a forged token using the server's public key as the HMAC secret. If the library uses one verification function that picks the algorithm from the token header, the forgery may pass. Pin the expected algorithm rather than trusting the header.

Weak Signing Secrets

HMAC-signed tokens are only as strong as their secret. A short or guessable secret can be brute-forced offline, letting an attacker mint valid tokens. Use long, random secrets, or prefer asymmetric keys.

Missing Claim Validation

A structurally valid signature is not enough. Failing to check the expiration (exp), issuer (iss), and audience (aud) claims lets attackers replay expired tokens or use a token intended for a different service.

JWT Security Best Practices

Validate Rigorously

  1. Pin the algorithm. Configure verification to accept only the specific algorithm your system uses, and never derive it from the token.
  2. Verify the signature against the correct key before trusting any claim.
  3. Check standard claims, including expiration, not-before, issuer, and audience, on every request.
  4. Reject unexpected tokens, such as unsigned tokens or those referencing an unknown key.

Keep Lifetimes Short and Plan for Revocation

Because a signed JWT is valid until it expires, it is hard to revoke. Use short-lived access tokens paired with longer-lived refresh tokens that can be invalidated server-side. Maintain a way to reject compromised tokens, such as a denylist or a rotating signing key.

Store Tokens Carefully

Where a token lives in a browser affects its risk. Storing tokens in localStorage exposes them to theft through cross-site scripting. Storing them in cookies with HttpOnly, Secure, and SameSite attributes, described in secure cookies, removes them from JavaScript's reach but requires CSRF protection. Choose based on your threat model.

Protect the Keys

Guard signing keys as critical secrets, rotate them periodically, and use a key identifier (kid) so you can roll keys without downtime. For asymmetric algorithms, distribute only the public key to verifiers.

Prefer Vetted Libraries and Weigh Alternatives

Implementing token verification by hand is a common source of the flaws above. Use a well-maintained library that validates the algorithm, signature, and claims by default, and configure the expected values explicitly rather than relying on assumptions. Where a use case does not truly need self-contained tokens, a traditional server-side session with an opaque identifier avoids much of this complexity, because revocation and validation happen naturally on the server.

JWTs in Context

JWTs are frequently issued by identity systems built on OAuth 2.0 and OpenID Connect, where the ID token is a JWT describing the authenticated user. Understanding how a token is issued, scoped, and validated across those flows is essential to using JWTs safely, because a perfectly signed token still grants too much if its claims are not constrained and checked. Treat a JWT as a signed assertion whose trustworthiness depends entirely on correct verification at every hop, not as an opaque secret that is safe merely because it is long and unreadable.

Key Takeaways

  • A JWT has three parts, header, payload, and signature, and the payload is only encoded, so it must not hold secrets.
  • The most common flaws are the alg none attack, algorithm confusion, weak HMAC secrets, and skipped claim checks.
  • Always pin the expected algorithm, verify the signature, and validate expiration, issuer, and audience.
  • Use short-lived access tokens with revocable refresh tokens, since signed JWTs are otherwise hard to revoke.
  • Store tokens according to your threat model and protect signing keys with rotation and key identifiers.
jwtauthenticationtokensweb-securityappsec

Frequently asked questions

What is a JSON Web Token (JWT)?

A JSON Web Token, or JWT, is a compact, self-contained format for transmitting digitally signed claims between parties, commonly used for authentication and authorization. It has three base64url-encoded parts: a header naming the algorithm, a payload of claims such as subject and expiration, and a signature over the first two. A server can verify the signature to trust the claims without a database lookup, enabling stateless sessions.

How do you secure a JSON Web Token?

Secure JWTs by pinning the expected signing algorithm instead of trusting the token header, verifying the signature against the correct key, and validating standard claims like expiration, issuer, and audience on every request. Use long random secrets for HMAC or asymmetric keys, keep access tokens short-lived, and rely on a well-maintained library configured with explicit expectations. Reject unsigned tokens and any algorithm you do not expect.

What are common JWT vulnerabilities?

Common JWT flaws include the alg none attack, where a server accepts an unsigned token and lets an attacker forge claims, and algorithm confusion, where a server expecting an asymmetric signature is tricked into verifying the token as HMAC using the public key. Others are weak, guessable HMAC secrets that can be brute-forced offline and missing claim validation that allows replaying expired or misdirected tokens. Most stem from validating tokens incorrectly.

Is data in a JWT encrypted?

No, a standard JWT payload is only base64url-encoded, not encrypted, so anyone who obtains the token can read its claims. The signature protects integrity, meaning tampering is detectable, but it does not provide confidentiality. Because of this, a JWT must never carry secrets or sensitive data in plaintext unless it is additionally encrypted using a scheme such as JWE.

Where should JWTs be stored in a browser?

Storing JWTs in localStorage exposes them to theft through cross-site scripting, since any injected script can read them, while storing them in cookies with HttpOnly, Secure, and SameSite attributes keeps them out of JavaScript's reach but requires CSRF protection. The right choice depends on your threat model and the other defenses in place. Whichever you pick, always serve tokens over HTTPS and keep their lifetimes short.

How do you revoke a JSON Web Token?

Because a signed JWT is valid until it expires, it cannot be revoked as easily as a server-side session. Common approaches are keeping access tokens short-lived and pairing them with longer-lived refresh tokens that can be invalidated on the server, maintaining a denylist of compromised token identifiers, or rotating the signing key to invalidate outstanding tokens. Planning for revocation up front avoids being unable to cut off a stolen token.

Try it hands-on

K0G is an open toolkit of browser-based security utilities — hashing, encoding, JWT, certificates, crypto and more, all running locally in your browser.

Explore the tools →