What Is a JWT?

A JSON Web Token is how most modern APIs prove "this request came from someone who already logged in" without the server having to remember anything. Here's what's actually inside one, and the two mistakes that account for most JWT-related security bugs.

reference guide auth JSON Web Token

// the shape of a jwt

A JWT is three Base64URL-encoded segments joined by dots: header.payload.signature. Base64URL is the same idea as regular Base64 (see the Base64 Converter) but swaps +// for -/_ so the token is safe to put directly in a URL or an HTTP header without escaping.

the three parts
headerwhich algorithm signed this token — e.g. {"alg":"HS256","typ":"JWT"}
payloadthe claims — who this token represents and when it expires
signatureproof the header + payload weren't tampered with since signing

// claims worth knowing

registered claims
ississuer — who created and signed this token
subsubject — who the token is about, usually a user ID
audaudience — who this token is intended for
expexpiration — a Unix timestamp; the token is invalid after this
nbfnot-before — the token isn't valid until this timestamp
iatissued-at — when the token was created

Everything past these is application-specific — roles, permissions, tenant IDs, whatever the issuer decided to include. There's no schema enforcement; the payload is just JSON, so anything the signer puts there arrives at the consumer as-is.

// symmetric vs asymmetric signing

HS256 uses one shared secret to both sign and verify — simple, but every service that needs to verify a token also needs the secret that can forge one. RS256 and ES256 use a private/public key pair: only the issuer holds the private key that signs tokens, while any number of services can hold the public key and verify without ever being able to mint a valid token themselves. For anything beyond a single trusted backend, asymmetric signing is almost always the right default.

// the two mistakes that matter

A JWT is encoded, not encrypted. Base64URL is trivially reversible by anyone — there is no key required to read a JWT's header or payload, only to verify its signature. Never put a password, secret, or anything sensitive directly in the payload; assume every claim is public the moment the token exists.
Always verify the signature server-side before trusting any claim. A client can send back any JWT-shaped string it wants, including one with exp pushed into the future or role: admin added by hand. The signature is the only thing that proves the payload wasn't altered after the real issuer signed it — reading claims without verifying first means trusting user input.

// try it yourself

Paste a token into the JWT Decoder to see its header and payload broken out, check exp/nbf against the current time, and verify HS256, RS256, or ES256 signatures — entirely in your browser, the token never leaves your machine.