← Back to the tool

Protocols · Under the hood

JWT builder & decoder

What each button in the tool actually computes, step by step — with the real formulas.

Encoding header and payload

"Build" first turns the fixed header object and your claims object into JSON text, then base64url-encodes each one separately (base64url is ordinary base64 with URL-unsafe characters swapped out and padding removed). Nothing here is encrypted — it's a length-preserving, fully reversible encoding.

Signing: HMAC over the literal string "header.payload"

The signing input isn't the header and payload objects — it's the literal ASCII string formed by joining their two base64url encodings with a single period. That exact string is what gets fed into HMAC-SHA256, using the same nested double-hash construction covered in the HMAC tool, alongside your secret.

signature=HMAC-SHA256(base64url(header)"."base64url(payload), secret)\text{signature} = \mathrm{HMAC\text{-}SHA256}(\text{base64url(header)} \,\|\, \texttt{"."} \,\|\, \text{base64url(payload)},\ \text{secret})

Decoding: split first, verify second

"Decode" does nothing cryptographic at all — it splits the token on its two dots and base64url-decodes the first two segments back into readable JSON. This is exactly why anyone can read a JWT's claims without knowing the secret: decoding and verifying are two entirely separate operations in this tool, and only the second one ever touches the signature.

Verifying: recompute, don't decrypt

"Verify signature" recomputes HMAC-SHA256 over the token's own header.payload string, using whatever secret you've entered, and compares the result to the signature segment already in the token — the same recompute-and-compare pattern as the HMAC tool, just applied to a specific, standardized signing input.

Now try it

Back to JWT builder & decoder

Build a real HMAC-signed JWT from your own claims, or paste one in to decode its header and payload and verify its signature.