# HS256 vs RS256 vs ES256: JWT Signing Algorithms

> HS256 signs JWTs with a shared secret; RS256 and ES256 use a private and public key pair. Key rules, measured signature sizes and when to use each.

- URL: https://generate.now/guides/hs256-vs-rs256-vs-es256
- Published by: Hyperdusk Ltd (https://hyperdusk.com)
- Published: 2026-11-11
- Last updated: 2026-11-11

## 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.

## Key differences

**HS256, RS256 and ES256 side by side**

|   | HS256 | RS256 | ES256 |
| --- | --- | --- | --- |
| Algorithm | HMAC using SHA-256 | RSASSA-PKCS1-v1_5 using SHA-256 | ECDSA using P-256 and SHA-256 |
| Kind | Symmetric | Asymmetric | Asymmetric |
| Key that signs | Shared secret | RSA private key | EC private key |
| Key that verifies | The same secret | RSA public key | EC public key |
| Key size required by RFC 7518 | 256 bits or more | 2048 bits or more | The P-256 curve |
| Signature size | 32 bytes | 256 bytes with a 2048-bit key | 64 bytes |
| Status in RFC 7518 | Required | Recommended | Recommended+ |

_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**

| Algorithm | Key | Signature | Signature as base64url | Whole token |
| --- | --- | --- | --- | --- |
| HS256 | 32-byte secret | 32 bytes | 43 characters | 183 characters |
| HS512 | 64-byte secret | 64 bytes | 86 characters | 226 characters |
| RS256 | RSA 2048-bit | 256 bytes | 342 characters | 482 characters |
| RS256 | RSA 4096-bit | 512 bytes | 683 characters | 823 characters |
| PS256 | RSA 2048-bit | 256 bytes | 342 characters | 482 characters |
| ES256 | P-256 | 64 bytes | 86 characters | 226 characters |
| ES384 | P-384 | 96 bytes | 128 characters | 268 characters |
| ES512 | P-521 | 132 bytes | 176 characters | 316 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

- [Decode, verify or sign a JWT](https://generate.now/jwt): JWT Decoder & Encoder. Decodes a token, checks its signature against a secret or public key, and signs payloads with the HS, RS, PS and ES algorithm families.
- [Generate a random 256-bit secret](https://generate.now/api-key): API Key Generator. Generates random keys in the browser, including 256-bit values suitable as an HS256 secret.

## Sources

Primary sources, read on 2026-11-11.

- [RFC 7518: JSON Web Algorithms (JWA)](https://www.rfc-editor.org/rfc/rfc7518): IETF. The alg values and their implementation status, HMAC and RSA key-size requirements, and the ECDSA signature format.
- [RFC 7519: JSON Web Token (JWT)](https://www.rfc-editor.org/rfc/rfc7519): IETF. The token format: header, payload and signature.
- [RFC 8725: JSON Web Token Best Current Practices](https://www.rfc-editor.org/rfc/rfc8725): IETF. The alg none and RS256-to-HS256 attacks, algorithm verification, key entropy and the ECDSA nonce guidance.

## Related guides

- [UUID v4 vs v7: Differences and Which to Use](https://generate.now/guides/uuid-v4-vs-v7): UUID v4 is 122 random bits. UUID v7 starts with a millisecond timestamp, so IDs sort by creation time. Bit layouts, collision odds and when to use each.
- [UUID vs ULID vs Nano ID: Size, Sorting and Collisions](https://generate.now/guides/uuid-vs-ulid-vs-nanoid): UUID, ULID and Nano ID compared: length, alphabet, random bits, whether they sort by time, and computed collision odds. With a guide to choosing one.
- [Password vs Passphrase: Which Is Stronger?](https://generate.now/guides/password-vs-passphrase): A random 12-character password and a six-word passphrase are about equally strong. Entropy tables for both, and what NIST SP 800-63B says about length.

[All guides](https://generate.now/guides)
