Tokens & JWTs
A track of P55 · OAuth 2.0 / OIDC & Federated Identity.
What a JWT is and how to verify one correctly — HS256 from scratch, the alg:none and key-confusion attacks, and disciplined exp/aud/iss checks.
Copy a JWT out of a request and paste it into any online decoder. It will show you the claims immediately: the user id, the roles, the expiry, all of it, with no key required. That surprises people the first time, and it should prompt the right question — if anyone can read a token, and the parts are just base64-encoded text, what stops anyone from writing one that says they are an administrator? The answer is a signature, and the entire security of the scheme rests on verifying it in a way that cannot be talked out of.
The track builds this from the inside. You will implement HS256 yourself — the header and payload encoded, an HMAC computed over them with a shared secret, appended as the third part — which makes it concrete that a JWT is signed and not encrypted, and that putting anything confidential in the payload is a mistake regardless of how well you verify it. With a working implementation in hand, you then break your own verifier twice, because both attacks are ones real libraries have shipped.
The first is alg:none. If your verifier reads the token's own header to decide
how to check the token, an attacker sets the algorithm to "none", drops the
signature, and your code cheerfully accepts a token they wrote. The second is
key confusion: a verifier that accepts either RS256 or HS256 based on the header
can be handed a token signed with HMAC using the server's public RSA key as
the shared secret — a value the attacker can freely obtain. Both share one root
cause, which is letting untrusted input decide how it will be validated, and one
fix: decide the algorithm and key before you look at the token. The track closes
on the checks that are skipped most often — exp, aud and iss — where a
token that is perfectly valid for a different audience is accepted by an API
that never asked who it was for.