JWT algorithms compared
The alg header names the JWS algorithm (RFC 7518) used to sign a token. Here is how the twelve common algorithms differ, which keys they need, and how to use them safely.
All algorithms
| alg | Family | Key | Signature |
|---|---|---|---|
| HS256 | HMAC using SHA-256 | Shared secret ≥ 256 bits | 32 bytes |
| HS384 | HMAC using SHA-384 | Shared secret ≥ 384 bits | 48 bytes |
| HS512 | HMAC using SHA-512 | Shared secret ≥ 512 bits | 64 bytes |
| RS256 | RSA signature (PKCS#1 v1.5) using SHA-256 | RSA key pair ≥ 2048 bits | = key size |
| RS384 | RSA signature (PKCS#1 v1.5) using SHA-384 | RSA key pair ≥ 2048 bits | = key size |
| RS512 | RSA signature (PKCS#1 v1.5) using SHA-512 | RSA key pair ≥ 2048 bits | = key size |
| PS256 | RSA-PSS signature using SHA-256 and MGF1 | RSA key pair ≥ 2048 bits | = key size |
| PS384 | RSA-PSS signature using SHA-384 and MGF1 | RSA key pair ≥ 2048 bits | = key size |
| PS512 | RSA-PSS signature using SHA-512 and MGF1 | RSA key pair ≥ 2048 bits | = key size |
| ES256 | ECDSA using P-256 and SHA-256 | EC P-256 key pair | 64 bytes |
| ES384 | ECDSA using P-384 and SHA-384 | EC P-384 key pair | 96 bytes |
| ES512 | ECDSA using P-521 and SHA-512 | EC P-521 key pair | 132 bytes |
No algorithm on this list is insecure by name. HS256 with a strong random 256-bit secret is perfectly sound; HS256 with the secret "secret" is not. The key and how it is managed matter more than the letters in alg.
Choosing an algorithm
- One service signs and verifies its own tokens? HS256 with a random 32-byte secret is simple and fast.
- Many services verify, one issues? Use an asymmetric algorithm so verifiers only need the public key. RS256 is the most widely supported; ES256 has much smaller keys and signatures; PS256 uses the more modern RSA-PSS padding.
- Interoperating with an identity provider? Use what it publishes — usually RS256.
Pin the algorithm
The classic algorithm confusion attack takes a token signed with RS256, changes the header to HS256, and signs it with the server's public key as the HMAC secret. A library that picks the algorithm from the token header and accepts the public key as an HMAC key will accept it. RFC 8725 §3.1 requires verifiers to decide which algorithms are acceptable and to bind each key to one algorithm:
// ✓ algorithm chosen by the verifier
jwtVerify(token, publicKey, { algorithms: ["RS256"] })
// ✗ algorithm chosen by the attacker
jwt.verify(token, key, { algorithms: [decodedHeader.alg] })The “none” algorithm
alg: "none" means the token is unsigned (RFC 7518 §3.6). It exists for contexts where integrity is guaranteed another way. A verifier must never accept it unless it was explicitly configured to — the decoder flags such tokens prominently.
Paste a JWT to see its algorithm, key ID and signature length checked against the specification.
Check a token's algorithm