DevKits

Comparison

JWT Algorithms: HS256 vs RS256 vs ES256

Choosing a JWT signing algorithm sounds trivial — HS256 is the default in most tutorials — but the wrong choice bakes an architecture into your system that becomes painful to change later. The core split is whether the party that verifies the token needs to also be able to sign it.

HS256 uses one shared secret for both. RS256 and ES256 split signing (private key) from verification (public key), which lets you distribute verifiers freely without giving them the power to mint tokens.

TL;DR

 HS256RS256ES256
TypeSymmetric (HMAC)Asymmetric (RSA)Asymmetric (ECDSA)
Signer keyShared secretRSA private keyEC private key
Verifier keySame shared secretRSA public keyEC public key
Key size≥32 bytes recommended2048 or 4096 bitsP-256 curve (256 bits)
Signature size32 bytes~256 bytes64 bytes
Sign speedFastestSlowestFast
Verify speedFastestFastFast
Multi-party verify without mintingNoYesYes

The options in depth

HS256 (HMAC-SHA-256)

Symmetric HMAC signing with a shared secret.

HS256 uses HMAC-SHA-256 with a shared secret to both sign and verify tokens. It is the simplest option and typically 2-5× faster than the asymmetric alternatives — a single hash operation per sign or verify.

The catch: any service that verifies also has the secret needed to mint tokens. If you deploy verification to 10 microservices, you have 10 places a leak can turn into a full-blown token forgery.

Good for

  • ·A single service that both signs and verifies (monolith)
  • ·Server-to-server tokens where the sender is fully trusted
  • ·Fast local test tokens

Avoid when

  • ·Multiple untrusted services must verify
  • ·You need to publish keys via JWKS

Try it: JWT Generator

RS256 (RSA-SHA-256)

The classic asymmetric choice — huge library support.

RS256 signs with an RSA private key and verifies with the matching public key. Because only the auth server holds the private key, you can safely publish the public key at a well-known JWKS endpoint and let every microservice, mobile client, and third party verify tokens on their own.

Downsides: keys are large (2048-4096 bits), signatures are ~256 bytes, and signing is the slowest of the three. Every OAuth provider (Auth0, Okta, Google) supports it, which is often the deciding factor.

Good for

  • ·Public JWKS with many independent verifiers
  • ·OAuth 2.0 / OIDC integrations
  • ·Any scenario where signing is centralized but verification is distributed

Avoid when

  • ·Bandwidth or token size matters (mobile with weak network)
  • ·Signing throughput is a bottleneck

ES256 (ECDSA-SHA-256 with P-256)

Modern asymmetric — same security as RS256, tiny keys and signatures.

ES256 uses ECDSA with the P-256 curve. It offers the same “split key” property as RS256, but with dramatically smaller keys (~64 bytes) and signatures (~64 bytes) — roughly 4× smaller than RS256, at similar or better security.

Adoption is now essentially universal in modern OAuth providers, mobile SDKs, and browser Web Crypto API. Apple's Sign in with Apple mandates ES256.

Good for

  • ·New systems — the modern default for asymmetric JWT
  • ·Mobile and low-bandwidth environments
  • ·Interop with modern OAuth providers (Apple, some Firebase flows)

Avoid when

  • ·You need to interop with legacy systems that only speak RS256

Which one should you pick?

Will only one service ever verify these tokens?

Use HS256. It is simplest and fastest.

Will multiple services (or third parties) need to verify?

Use asymmetric. Prefer ES256 for new work, RS256 for compatibility.

Is this a new system without legacy constraints?

Use ES256. Same security as RS256 at ~1/4 the size.

Are you integrating with an existing OAuth provider?

Use whatever they support. RS256 is universal; ES256 is now widely available too.

Common pitfalls

  • Never accept the `none` algorithm — a classic JWT vuln. Explicitly whitelist algorithms in your verifier.
  • Confused-deputy attack: never verify with the wrong algorithm class. Some libraries in the past accepted `HS256` with an RSA public key as HMAC secret, letting attackers forge tokens with the public key.
  • HS256 secrets < 32 bytes weaken the signature. Use 32/48/64 bytes for HS256/384/512.
  • Rotating an HS256 secret requires simultaneous update on every service. RS256/ES256 lets you rotate keys via JWKS without downtime.

Frequently Asked Questions

Is HS256 less secure than RS256?

No — the cryptographic strength is similar. The difference is architectural: HS256 requires sharing the secret with every verifier, which increases exposure surface.

Why is ES256 signature 64 bytes if the curve is 256 bits?

An ECDSA signature is a pair (r, s), each 32 bytes for P-256, giving 64 bytes total. RSA signatures are the modulus size — 256 bytes for RSA-2048.

Can I switch from HS256 to RS256 later?

Yes, but you must reissue all in-flight tokens (they don't cross algorithms) and update every verifier's key material.

What about EdDSA / Ed25519?

EdDSA is even better than ES256 (faster, deterministic, no bad random number generator failure mode). Support is growing but not yet universal — check your library before adopting.

Related comparisons