JWT security failures rarely come from an attacker breaking modern cryptography. They come from applications that verify too little, trust the wrong key, expose bearer tokens, or expect a self-contained token to behave like a server-controlled session. The format is compact, but the surrounding decisions form a complete authentication system and deserve the same rigor as any other security boundary.

Decoding is not verification

Libraries and online tools can decode a JWT header and payload without a key. Applications sometimes read those claims and treat them as trusted before checking the signature. An attacker can create a token containing any user ID or role they want. Until verification succeeds, every claim is untrusted input.

Verification must happen before authorization logic. The application should reject malformed tokens, invalid signatures, disallowed algorithms, unknown issuers, wrong audiences, expired tokens, and tokens that are not active yet.

Never let the token choose the security policy

The header names a signing algorithm, but the verifier must compare it with an allowlist configured for that issuer and key. Historically, permissive libraries accepted unsigned tokens or confused symmetric and asymmetric algorithms. Secure code does not accept whatever algorithm the incoming token requests.

Key identifiers also require care. A kid value may help select a trusted key, but it must not become an unchecked file path, database fragment, or arbitrary remote URL. Key lookup should stay within a controlled set published by the expected issuer.

Bearer tokens must be treated like credentials

Most access JWTs are bearer tokens: possession is enough to use them. A valid signature does not identify the person presenting the token. Tokens can leak through logs, browser storage, analytics tools, error reports, URLs, and copied commands.

Use TLS, avoid placing tokens in URLs, redact authorization headers from logs, and keep access-token lifetimes short. In browsers, storage choices should reflect cross-site scripting and cross-site request risks. No storage location fixes a vulnerable application, so reduce exposure and apply layered defenses.

Long lifetimes make revocation painful

A self-contained token can remain valid after a password change, employee departure, or permission removal. A one-week access token gives an attacker a one-week opportunity unless every service checks a revocation system, which removes much of the stateless benefit.

Short-lived access tokens limit exposure. Longer-lived refresh tokens can obtain new access tokens through a more controlled endpoint and should support rotation and revocation. High-risk events may require invalidating sessions or checking a token version maintained by the account system.

Do not place secrets or excessive data in the payload

A signed JWT payload is readable. Passwords, private keys, confidential profile data, and internal secrets do not belong there. Even ordinary personal information should be minimized because tokens spread through clients and services and may be retained in diagnostic systems.

Large tokens also create operational problems. They increase request size, may exceed proxy or cookie limits, and duplicate stale state on every call. Include claims that verifiers genuinely need and fetch changing details from authoritative services when necessary.

Validate issuer, audience, and time together

A correct signature from a known key is insufficient if the token was created for another application. Validate the issuer against an exact expected value and confirm that the current service belongs to the audience. Apply expiration and not-before checks with a small, documented clock-skew allowance rather than ignoring time failures.

Multi-tenant systems should ensure tenant claims agree with routing and account context. Authorization decisions should use server-defined rules, not simply accept a role string because it appears in a signed payload.

Key rotation must be designed before an incident

Keys expire, leak, and need replacement. Issuers should publish current verification keys, identify them reliably, protect private signing keys, and allow enough overlap for tokens signed by the previous key to expire. Verifiers need caching behavior that updates promptly without failing whenever the key endpoint is temporarily unavailable.

Emergency rotation requires a plan for invalidating compromised keys and understanding which tokens remain accepted. Practicing that process is more valuable than assuming a breach will never occur.

Authorization still belongs to the application

A token may carry roles or scopes, but the application must translate those claims into permission checks for the requested resource. A signed claim that says editor does not automatically prove that the user may edit every tenant, project, or document. Object-level authorization remains essential.

Keep authorization rules close to authoritative domain data and test them independently from token parsing. JWT validation establishes a trustworthy identity context; it does not answer every question about what that identity may do.

Use maintained libraries and test rejection paths

JWT parsing and cryptographic verification should be handled by a well-maintained library. Configuration still matters: specify algorithms, claims, and keys explicitly. Tests should prove that the application rejects altered payloads, expired tokens, wrong audiences, unexpected issuers, unsigned tokens, and tokens signed with unrelated keys.

A secure JWT implementation is intentionally strict. It knows exactly who may issue tokens, which algorithms and keys are valid, where a token may be used, and how long it remains acceptable. Everything else is rejected, even when it can be decoded successfully.