What a JWT actually is, and why decoding one isn't the same as trusting it

Every JWT you'll ever see is readable by anyone with no key and no permission at all — the security lives entirely in a separate step almost nobody looks at, called verification.

Three parts, two dots, and one crucial thing missing

A JSON Web Token is three sections of text separated by two periods: a header, a payload, and a signature — written out, it looks like a long run of gibberish with two dots in it (eyJhbGci... .eyJzdWIi... .SflKxwRJ...). The header and payload are not encrypted or hashed in any way — they're plain JSON text run through base64url encoding, which is a reversible text-to-text transformation, not a cipher. Anyone, with no password, no key and no special tool beyond a text editor, can decode the header and payload of any JWT they can see.

This is intentional and not a flaw. A JWT is designed to be inspected by every system that receives it — a server needs to read the payload's claims (who the user is, what they're allowed to do, when the token expires) without necessarily contacting the system that issued it first. Encrypting the payload would defeat that purpose for the overwhelming majority of JWT use cases, which don't need the payload kept secret from the systems reading it, only kept from being tampered with.

The signature is the only part that resists tampering

The third section, the signature, is what actually protects a JWT from being forged or altered — it's a cryptographic signature computed over the header and payload using a secret key (for HMAC-based algorithms like HS256) or a private key (for public-key algorithms like RS256 or ES256). Changing even one character of the payload — say, editing a user role from "user" to "admin" in the decoded JSON and re-encoding it — produces a token whose signature no longer matches, and any system that actually checks the signature will reject it.

Verification is the step that checks this: recomputing the expected signature from the header and payload using the correct key, and comparing it against the signature actually attached to the token. A system that decodes a JWT's payload and trusts its contents without performing this check is not verifying anything — it's reading a note anyone could have written, formatted to look official.

Decoding versus verifying
StepNeeds a key?Proves what?
DecodingNoThe token is well-formed JSON, formatted correctly
VerifyingYesThe token's contents haven't been altered since it was signed by someone holding the correct key

The vulnerability this confusion actually causes

A well-documented real class of JWT vulnerability comes directly from this decode-versus-verify confusion: some poorly-written server code decodes a JWT, reads a role or permission claim from the payload, and acts on it — without ever calling the library function that actually verifies the signature. Since the payload is trivially readable and editable by anyone, an attacker who understands this can hand-craft a token claiming to be an administrator, and a server with this bug will accept it, because nothing ever checked whether the signature matched.

A related, historically real attack targets the header's own "alg" (algorithm) field, which is also just plain readable JSON: some early JWT libraries would use whatever algorithm the token's own header claimed, including a literal "none" value meaning no signature at all — an attacker could set alg to none, strip the signature section entirely, and have a buggy library accept a completely unsigned, freely-editable token as valid. Modern JWT libraries fix this by requiring the calling code to specify which algorithm it expects, rather than trusting the token to declare its own, but the historical vulnerability is exactly why security guidance still warns against ever trusting a token's self-declared algorithm.

Symmetric-key verification (HS256 and similar) needs the same secret used to sign the token, so it can only be checked by a system that holds that secret — typically the same server that issued it, not a general-purpose public decoder. Public-key algorithms (RS256, ES256) can be verified by anyone holding the public key, which is why some tools do offer real client-side verification for those specifically.

Where this comes from

  • The JWT format and its three-part structure are defined in RFC 7519 (JSON Web Token) and the related RFC 7515 (JSON Web Signature).
  • The alg:none vulnerability and the general decode-vs-verify confusion are documented security issues covered extensively by OWASP and in JWT library security advisories from the mid-2010s onward.