A JWT, or JSON Web Token, is a compact, URL-safe string that packages a set of claims — statements about a user, a service, or a session — along with a cryptographic signature that lets a receiving system verify the claims haven't been altered. If you're asking what is a JWT in the context of modern authentication, the short answer is this: it's a self-contained credential that carries its own proof of authenticity, so a server doesn't need to look up a session record to trust it. A JWT consists of three base64url-encoded segments separated by dots — a header describing the signing algorithm, a payload holding the claims, and a signature computed over the first two parts. Because the payload is only encoded, not encrypted, anyone can read it; the signature is what determines whether it can be trusted. That distinction — readable but not necessarily writable — is the source of both the format's popularity and most of its security incidents.
What Is a JWT, Exactly?
A JWT is a standardized (RFC 7519) way to represent claims securely between two parties, typically an identity provider and an application. Structurally, it's three parts: header.payload.signature. The header specifies metadata like the signing algorithm (alg) and token type (typ); the payload holds registered claims (iss, sub, exp, aud) plus whatever custom data an application wants to attach, such as a user ID or role; the signature binds the header and payload together using either a shared secret (HMAC) or a private/public key pair (RSA, ECDSA). A typical login flow looks like this: a user authenticates with a username and password, the server issues a JWT signed with its private key, and the client attaches that token to the Authorization: Bearer header on every subsequent request. Any service holding the corresponding public key — or shared secret — can independently verify the token without calling back to the issuer, which is precisely why JWTs became the default choice for stateless APIs and microservices that need to avoid a shared session store.
How Does JWT Signature Verification Work?
JWT signature verification works by recomputing the signature over the received header and payload and comparing it to the signature attached to the token, rejecting anything that doesn't match byte-for-byte. Concretely, a verifier takes the base64url-decoded header and payload, re-signs them using the algorithm named in the header and the key it has on file, and checks the result against the token's third segment. If the algorithm is HMAC-SHA256 (HS256), the verifier needs the same secret the issuer used. If it's RSA or ECDSA (RS256, ES256), the verifier only needs the issuer's public key, which is the model most identity providers — Auth0, Okta, AWS Cognito — use so that downstream services can validate tokens without ever holding a private key. Verification libraries also check the exp (expiration), nbf (not before), aud (audience), and iss (issuer) claims, because a cryptographically valid signature says nothing about whether the token is expired, meant for a different service, or issued by someone else entirely. A shockingly common real-world bug is skipping that claim validation step: a token signed correctly by IdP A can still be replayed against Service B if Service B never checks that aud matches its own identifier.
What Is the JWT Algorithm Confusion Attack?
The JWT algorithm confusion attack is a forgery technique that abuses the fact that the token itself declares which algorithm was used to sign it, and some libraries trust that declaration instead of enforcing what the application expects. The classic case: a server issues tokens signed with RS256, using a private key it keeps secret and a public key it happily publishes at a .well-known endpoint or embeds in client code. An attacker who obtains that public key crafts a new token, sets the header's alg field to HS256, and signs the token using the public key as an HMAC secret. If the verification library naively reads alg from the attacker-controlled header and calls the matching verification routine, it ends up running an HMAC check using the public key as the secret — a key the attacker also has — and the forged token validates successfully. This exact class of bug was disclosed across multiple mainstream JWT libraries in 2015 and 2016 (affecting node-jsonwebtoken and others) and remains a staple finding in penetration tests today. A closely related variant is the alg: none attack, where an attacker strips the signature entirely and sets the algorithm to none; older or misconfigured libraries that treat "none" as a valid, unsigned algorithm will accept the token outright. The fix in both cases is the same: the verifier, not the token, should decide which algorithm and which key are acceptable, and mismatches should be rejected outright.
Is a JWT More Secure Than a Session Token?
Neither JWTs nor server-side session tokens are inherently more secure — they trade off differently, and the JWT vs session token decision is really about revocation, statefulness, and attack surface rather than raw security. A traditional session token is an opaque random string that maps to a record in server-side storage (Redis, a database); the server can invalidate it instantly by deleting that record, but every request requires a storage lookup, which doesn't scale as cleanly across distributed services. A JWT is self-verifying and needs no lookup, which is great for performance and for microservice architectures, but it also means a token issued with a two-hour expiry stays valid for two hours even if the user is logged out, the account is compromised, or a permission is revoked in the interim — there's no central record to delete. Teams try to patch this with short expirations plus refresh tokens, or with server-side denylists that reintroduce the statefulness JWTs were meant to avoid. In practice, session tokens tend to be the safer default for traditional web apps with a single backend, while JWTs earn their keep in federated or service-to-service scenarios where avoiding a shared session store outweighs the cost of harder revocation.
What Does JSON Web Token Security Actually Depend On?
JSON Web Token security depends almost entirely on how rigorously the signature is verified and how tightly the signing keys are controlled, not on the token format itself. The format has no inherent confidentiality — payload contents are visible to anyone who intercepts the token, so secrets, passwords, or sensitive PII should never be placed in claims. Beyond that, the most common real-world failures are: trusting the algorithm declared in the token header (enabling algorithm confusion), skipping expiration or audience checks, using weak or hardcoded HMAC secrets that can be brute-forced offline, and failing to rotate signing keys after a suspected leak. A widely cited example is a 2019 disclosure affecting several JWT-based single sign-on implementations where a hardcoded or default HMAC secret shipped in example code made it into production, letting anyone forge arbitrary admin tokens once the secret was found in a public repository. Strong JWT security practices include pinning the expected algorithm on the verifier side, using asymmetric signing (RS256/ES256) wherever tokens cross trust boundaries, keeping expirations short, validating every registered claim, and treating signing keys with the same operational rigor as any other production secret — versioned, rotated, and never checked into source control.
How Does a JWT Get Compromised in Practice?
A JWT gets compromised most often through leaked signing secrets, algorithm confusion bugs, or simple theft of a valid token rather than through any flaw in the base64 or cryptographic scheme itself. Secrets end up in git history, CI logs, or client-side JavaScript bundles far more frequently than they're brute-forced. Tokens themselves get stolen through XSS when they're stored in localStorage instead of an HttpOnly cookie, through logging middleware that inadvertently writes Authorization headers to application logs, or through man-in-the-middle interception on connections that don't enforce TLS. Because a stolen JWT is bearer-only — anyone holding the string can use it until it expires — a leaked long-lived token can be as damaging as a leaked password, with the added wrinkle that many teams have no mechanism to revoke it early. This is why the software supply chain angle matters as much as the application-layer one: a compromised dependency, a misconfigured secrets manager, or a leaked .env file in a CI pipeline can expose the exact signing key that underwrites every token an organization issues.
How Safeguard Helps
Safeguard approaches JWT risk as a supply chain problem, not just an application security one, because most real-world JWT compromises trace back to how signing keys and secrets move through build pipelines, repositories, and third-party dependencies. Safeguard continuously scans source repositories, CI/CD configurations, and container images for hardcoded JWT secrets, exposed private keys, and vulnerable versions of JWT libraries known to be affected by algorithm confusion or alg: none issues, flagging them before they reach production. It maps the dependency graph behind your authentication stack so you know exactly which JWT libraries are in use, whether they're pinned to secure versions, and whether a newly disclosed CVE in a signing or verification library touches a service that issues real user tokens. For teams enforcing least-privilege secret access, Safeguard correlates where signing keys are stored and consumed across environments, surfacing cases where a production key is reachable from a lower-trust pipeline — the same pattern behind several public JWT-secret leaks. The goal isn't to replace your identity provider or your verification logic; it's to make sure the keys, dependencies, and pipelines underneath that logic are never the weakest link in an otherwise sound JWT implementation.