Security

JWT signing (HS256, RS256)

How a JWT's signature is made. HS256 signs and checks with one shared secret (HMAC with SHA-256), while RS256 signs with an RSA private key that stays with the issuer and checks with a public key anyone can hold.

What actually gets signed

The signer takes the Base64url header, a dot and the Base64url payload, and runs that string through the algorithm named in alg. The result becomes the third part of the token. Change any character in the first two parts and the signature no longer matches.

The algorithm decides what the result looks like:

  • HS256: HMAC with SHA-256, a 32-byte signature, 43 Base64url characters
  • ES256: ECDSA on the P-256 curve with SHA-256, a 64-byte signature, 86 characters
  • RS256: RSA with SHA-256, a signature as long as the key. A 2048-bit key gives 256 bytes and 342 characters

The 256 in all three names is the SHA-256 hash, not the key size.

HS256: one secret does both jobs

HS256 signs and verifies with the same shared secret. That's simple, and it's the one algorithm RFC 7518 marks as required for every implementation. The catch is that every service that can verify a token can also create one. If any of them leaks the secret, an attacker can mint tokens for all of them.

The secret has to be random. RFC 7518 requires a key at least as large as the hash output, so 256 bits for HS256. RFC 8725 adds that a password a person can memorize must not be used directly as the key, since anyone holding one token can test guesses against its signature offline. A 12-character password from every class has 78 bits, well short of 256. Generate 32 random bytes with a CSPRNG instead. The HS256 secret length guide goes through key sizes.

RS256 and ES256: a key pair

With RS256 the issuer signs with a private key and everyone else verifies with the public key. A leaked public key is harmless, so APIs, gateways and partners can check tokens without being able to forge them. RFC 7518 requires an RSA key of 2048 bits or larger. ES256 does the same job with a P-256 elliptic curve key. Its signature is 64 bytes against 256 for RSA, 4 times smaller.

Verifiers find the right public key through a JWKS endpoint, a JSON set of keys. The token's kid header says which key signed it, and that's what makes rotation work: publish the new key, start signing with it and retire the old one once old tokens expire. The JWKS and kid guide shows how a verifier picks the key.

Choosing, and pinning the algorithm

Use HS256 when one service issues and checks its own tokens. Use RS256 or ES256 as soon as another service, a partner or the public has to verify them. The HS256 vs RS256 comparison goes through the tradeoffs.

Whichever you pick, fix the accepted algorithm in the verifier. RFC 8725 says each key must be used with exactly one algorithm. A verifier that believes the token's own alg can be told to skip the signature with none, or to check an RS256 token as HS256 using the public key as the HMAC secret. Algorithm confusion walks through that second attack.

Work it out yourselfOpen the JWT Decoder & Validator

Sources

Back to the glossary