Understanding JSON Web Tokens: signing with JWS

In the previous part we assembled a header and a payload. On their own they prove nothing. A signature is what turns them into something a recipient can act on.

What a signature buys you

RFC 7515 defines JSON Web Signature. It gives you integrity, the payload has not been altered, and non-repudiation, the issuer cannot deny having written it. It gives you no confidentiality at all: the payload is base64url, which anyone can decode.

The three parts

The compact serialisation is the form everybody recognises: three chunks separated by dots.

BASE64URL(header) . BASE64URL(payload) . BASE64URL(signature)

What gets signed is not the payload alone. It is the string header.payload, dots included, after base64url encoding. That detail matters: it means the header is covered by the signature, so nobody can change the declared algorithm without breaking it.

Protected and unprotected headers

JWS distinguishes two header sets. The protected header is covered by the signature. The unprotected header is not: it travels alongside, and anyone can rewrite it in flight.

The compact form has no unprotected header at all, which is one reason it is the safe default. The JSON forms allow both, and that is where implementations get into trouble. Read what happens when a verifier takes alg from the wrong one: it is not theoretical, it was a real vulnerability in this library.

The mandatory header

One header member is required: alg, the signature algorithm. HS256 for an HMAC with SHA-256, RS256 for RSASSA-PKCS1-v1_5, ES256 for ECDSA on P-256, EdDSA for Ed25519. Which to pick deserves its own article.

The specification also defines alg: none, an unsigned token. Never accept it on verification. A verifier that honours the token’s own claim of being unsigned accepts anything.

Several signatures on one payload

The JSON serialisation allows more than one signature over the same payload, each with its own algorithm and key. That is how you serve two audiences, one verifying with a shared secret and another with a public key, without issuing two tokens.

The compact form cannot express this. If you need it, you need the JSON form, and you lose the ability to put the token in a URL.

Next

Signing proves who wrote the payload. It does not hide it. The next part covers encryption.