Skip to content

HS256 vs RS256 vs ES256: JWT Signing Algorithms

Last updated Published by Hyperdusk Ltd

The short answer

HS256 signs a JWT with one shared secret, so every party that can verify a token can also create one. RS256 and ES256 sign with a private key and verify with a public key. RS256 uses RSA and produces a 256-byte signature with a 2048-bit key. ES256 uses the P-256 elliptic curve and produces a 64-byte signature.

Decode, verify or sign a JWT →

Key differences

HS256, RS256 and ES256 side by side
HS256RS256ES256
AlgorithmHMAC using SHA-256RSASSA-PKCS1-v1_5 using SHA-256ECDSA using P-256 and SHA-256
KindSymmetricAsymmetricAsymmetric
Key that signsShared secretRSA private keyEC private key
Key that verifiesThe same secretRSA public keyEC public key
Key size required by RFC 7518256 bits or more2048 bits or moreThe P-256 curve
Signature size32 bytes256 bytes with a 2048-bit key64 bytes
Status in RFC 7518RequiredRecommendedRecommended+
Algorithm names and status are from the table in RFC 7518, section 3.1. The "+" means the requirement is likely to be strengthened in a future version.

What is the difference between symmetric and asymmetric signing?

With HS256 there is one key. The issuer computes an HMAC over the token's header and payload with a secret, and the verifier recomputes it with the same secret. Anything that can check a token therefore holds the key that can forge one. That is acceptable when the issuer and the verifier are the same service, and a risk when the secret has to be copied to several services.

With RS256 and ES256 there are two keys. The issuer signs with a private key that never leaves it, and anyone can verify with the matching public key. Verifiers cannot mint tokens, and the public key can be published.

How big is the signature, and the token?

The signature is the third part of a JWT, so its size is added to every request that carries the token. An HMAC signature is as long as its hash output, an RSA signature is as long as the key, and an ECDSA signature is two integers the size of the curve.

Signature and token size by algorithm
AlgorithmKeySignatureSignature as base64urlWhole token
HS25632-byte secret32 bytes43 characters183 characters
HS51264-byte secret64 bytes86 characters226 characters
RS256RSA 2048-bit256 bytes342 characters482 characters
RS256RSA 4096-bit512 bytes683 characters823 characters
PS256RSA 2048-bit256 bytes342 characters482 characters
ES256P-25664 bytes86 characters226 characters
ES384P-38496 bytes128 characters268 characters
ES512P-521132 bytes176 characters316 characters
Measured by signing the same four-claim payload (sub, name, iat, exp) with the jose library, version 6.2.3, on Node.js 24 and verifying each result. The header and payload take 139 characters in every row. The ECDSA sizes match the 64, 96 and 132 octets given in RFC 7518.

Public keys differ in the same direction. Exported in the standard SPKI format, the RSA 2048-bit public key from that test was 294 bytes and the P-256 public key was 91 bytes.

What are the key requirements?

RFC 7518 says an HS256 key MUST be at least as long as the hash output, 256 bits, and that RSA keys MUST be 2048 bits or larger. ES256 always uses the P-256 curve.

For HS256 the quality of the secret matters as much as its length. RFC 8725, the JWT best-practices document, says human-memorizable passwords MUST NOT be used directly as an HS256 key: once an attacker has one token, a weak secret can be guessed offline. Use at least 32 bytes from a cryptographically secure random source.

Libraries do not always enforce these rules. In the same test, jose 6.2.3 refused an RSA key under 2048 bits but signed an HS256 token with an 8-byte secret.

Which attacks target the alg header?

A JWT names its own signing algorithm in the alg header, and RFC 8725 describes two attacks that abuse this. In the first, an attacker changes alg to none, and a library that trusts the header accepts the token without checking any signature. In the second, a token meant for RS256 is relabelled HS256, and a library verifies it with HMAC using the RSA public key, which is not secret, as the shared secret.

The fix is the same for both: the verifier decides which algorithms it accepts instead of reading that from the token. RFC 8725 says libraries MUST let the caller specify a supported set of algorithms, and that each key MUST be used with exactly one algorithm.

Is ES256 better than RS256?

It is smaller. In the table above an ES256 token is 226 characters where the RS256 one is 482, and the public key is about a third of the size. RFC 7518 also marks ES256 as "Recommended+" where RS256 is "Recommended".

ES256 has one requirement RS256 does not. ECDSA needs a unique random value for every signature, and RFC 8725 warns that if those values are predictable the private key may be recoverable. It says libraries SHOULD use the deterministic method in RFC 6979. That is the library's job, not something you set per token.

RS256 remains a reasonable choice when a verifier you do not control only supports RSA. RFC 7518 defines both.

Which should you use?

Use HS256 when one service both issues and verifies its tokens and the secret is long, random and stored in one place. Use an asymmetric algorithm as soon as a second party needs to verify tokens, so that verifying does not require the power to issue.

Between the two, choose ES256 for smaller tokens and keys, and RS256 where the systems that verify your tokens require RSA. Whichever you choose, configure the verifier with an explicit list of accepted algorithms.

Tools for this

Sources

This page was written from the primary sources below, read on .

Published by Hyperdusk Ltd. Last updated . Figures in computed tables were produced by the method stated under each table.

All guides→