100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
API Security
32 minintermediate

JWTs: Signing, Validation and the Classic Mistakes

A JSON Web Token is three base64url-encoded segments joined by dots: a header describing the signing algorithm, a payload of claims, and a signature computed over the first two. That signature is the entire security property a JWT gives you — proof that whoever holds the signing key produced this exact header and payload, and that neither has changed since. Everything this lesson covers is what happens when a service trusts a JWT for more than that one guarantee, or fails to actually check the guarantee it does offer.

The first misconception to retire is that a JWT is confidential. Base64url is an encoding, not an encryption scheme — anyone holding a token can decode the payload in a text editor and read every claim in it. A JWT proves the payload wasn't tampered with; it does nothing to hide that payload from the party carrying it. Put a role name or a user ID in a JWT and you've made a design choice; put a secret in one and you've made a mistake, because the client, any proxy that logs request headers, and anyone who captures the token all get to read it.

The second misconception is that verifying a JWT means checking the signature. Checking the signature proves integrity. It says nothing about whether the token is still within its validity window, was minted for this service rather than a neighbouring one, or came from an issuer this service actually trusts. A service that verifies the signature and stops there has done half the job, and every claim below shows what the other half buys you.

The classic JWT vulnerabilities — accepting `alg: none`, algorithm confusion between RS256 and HS256, trusting a `kid` or `jku` header to pick its own key, and skipping claim checks after a valid signature — are not flaws in the JWT format. They are validation steps a verifying service skipped, almost always because a library made the insecure path the path of least resistance. Knowing exactly which checks the format leaves to you is what separates a JWT integration that's actually safe from one that merely looks like it is.

Analogy🏏Cricket
🏏 Think of it like cricket: A scorecard signed and stamped by the match referee at the end of a day's play carries real weight — it's the official record, and a team disputing a result has to reckon with that stamp. A scorecard someone scribbled in the stands and photocopied carries none of that weight, no matter how neatly it's formatted or how convincingly it lists the same scores, because there's no verified signature behind it tying it to the actual authority. Now picture a naive clerk at league headquarters who accepts any scorecard as official provided it merely has a signature-shaped mark on it, without checking that mark against the referee's actual seal — a forger only needs to draw something in the right box, not obtain the referee's real seal at all. That's exactly what a server does when it accepts a JWT with `alg: none` or verifies a signature without pinning which algorithm and which key were supposed to produce it: it's checking that a signature-shaped thing exists, not that it came from the authority it claims to. A JWT's signature is only as trustworthy as the specific, pre-agreed verification process applied to it — a referee's seal checked against a known reference is trustworthy; a mark merely present in the signature box is not. The discipline this lesson teaches is building the clerk who checks the seal against a known reference every time, never the clerk who accepts whatever shows up in the box.
Lesson 7 of 35
0% complete