FmtDev
Language
Back to blog
March 25, 2026

HS256 vs RS256: Which JWT Algorithm Should You Use?

A practical comparison of HS256 and RS256 JWT signing algorithms. Learn when to use symmetric vs asymmetric signing, the security tradeoffs, and which algorithm fits your architecture.

The Algorithm Choice That Defines Your JWT Security

Every time a server creates a JWT, it has to make a critical decision: which algorithm should sign this token?

The two most common choices are HS256 (symmetric) and RS256 (asymmetric). Most developers pick one without fully understanding the tradeoffs. That choice affects everything — from how your secrets are managed to how vulnerable your system is to specific attacks.

This guide breaks down both algorithms, explains when to use each one, and shows you the security risks of choosing wrong.

What HS256 Actually Does

HS256 stands for HMAC-SHA256. It is a symmetric algorithm, meaning the same secret key is used to both sign and verify the token.

Server signs token:    HMAC-SHA256(header + payload, SECRET_KEY)
Server verifies token: HMAC-SHA256(header + payload, SECRET_KEY)

The same key does both jobs.

When HS256 Works Well

  • Single server applications where only one service signs and verifies tokens
  • Internal microservices where all services are trusted and share the same secret
  • Simple auth flows where key distribution is not a concern

The HS256 Risk

If the secret key is weak, short, or predictable, it can be brute-forced. A modern GPU running Hashcat can test billions of HMAC-SHA256 combinations per second.

Real benchmarks:

| Key Length | Key Type | Crack Time (RTX 4090) | |---|---|---| | 6 characters | lowercase | under 1 second | | 8 characters | mixed case | under 1 hour | | 12 characters | random | ~200 years | | 32 bytes | random | heat death of universe |

The entire security of HS256 depends on one thing: the strength of your secret key.

If you use HS256, your secret must be at least 256 bits (32 bytes) of cryptographically random data. Generate it like this:

openssl rand -base64 32

Never use human-readable strings like "secret", "password123", or "my-jwt-key".

What RS256 Actually Does

RS256 stands for RSA-SHA256. It is an asymmetric algorithm, meaning it uses two different keys:

  • A private key to sign the token (kept secret on the auth server)
  • A public key to verify the token (can be shared with anyone)
Auth server signs:     RSA-SHA256(header + payload, PRIVATE_KEY)
Any service verifies:  RSA-SHA256(header + payload, PUBLIC_KEY)

When RS256 Works Well

  • Distributed systems where multiple services need to verify tokens but only one service should create them
  • Third-party integrations where you want external services to verify tokens without sharing your signing secret
  • Public APIs where token verification needs to happen without exposing sensitive keys
  • OAuth / OpenID Connect flows where identity providers publish public keys via JWKS endpoints

The RS256 Advantage

Even if someone has the public key (which is designed to be public), they cannot forge tokens. Only the private key can sign. This eliminates an entire class of attacks.

The Critical Difference

HS256 (Symmetric):
  Sign:   SECRET_KEY
  Verify: SECRET_KEY  ← same key
  Risk:   Anyone with the key can sign AND verify

RS256 (Asymmetric):
  Sign:   PRIVATE_KEY  ← secret
  Verify: PUBLIC_KEY   ← public
  Risk:   Only private key holder can sign

With HS256, every service that can verify tokens can also forge tokens. If any service is compromised, the attacker can create tokens for any user.

With RS256, even if a verification service is compromised, the attacker cannot forge tokens because they don't have the private key.

The Algorithm Confusion Attack

This is where the choice between HS256 and RS256 becomes a real security vulnerability.

If a server accepts both HS256 and RS256, an attacker can:

  1. Take a legitimate RS256-signed token
  2. Change the header to say "alg": "HS256"
  3. Sign the modified token using the public key as the HMAC secret
  4. Send it to the server

The server sees alg: HS256 and thinks: "I need to verify with the shared secret." It grabs the key it has on file — which is the public key. The attacker signed with the public key. The signatures match. The forged token is accepted.

This is a real vulnerability documented in CVE-2016-10555 affecting the popular jsonwebtoken npm library.

How To Prevent It

Never let the token header decide which algorithm to use.

Your server must enforce a specific algorithm:

// Node.js example
jwt.verify(token, publicKey, { algorithms: ['RS256'] });

Hardcode the algorithm. Whitelist exactly one. Ignore whatever the token header says.

Which One Should You Use?

Use HS256 if:

  • You have a single server or a small trusted cluster
  • All services that verify tokens are under your direct control
  • You can guarantee your secret key is strong (256-bit random)
  • You want simpler key management
  • Performance matters (HS256 is faster than RS256)

Use RS256 if:

  • Multiple services need to verify tokens
  • You have third-party services or external APIs
  • You use OAuth or OpenID Connect
  • You want to publish verification keys without security risk
  • You need to rotate keys without coordinating across all services
  • Security is more important than performance

The General Rule

Small internal app → HS256 with a strong secret
Anything distributed or public-facing → RS256

If you are unsure, choose RS256. It is harder to misconfigure fatally.

Inspecting Your JWT Algorithm Safely

When debugging JWTs, you need to check which algorithm was used. The algorithm is in the token header.

Never paste tokens into online JWT decoders. Your token contains authentication credentials. If the token is still active, you are handing a live key to a third-party server.

Use a local, client-side decoder that processes everything in your browser without sending data anywhere.

Try the FmtDev JWT Decoder — everything runs locally. Your token never leaves your machine.

Security Checklist

Regardless of which algorithm you choose:

  1. Enforce the algorithm server-side — never trust the token header
  2. Use strong keys — 256-bit random for HS256, 2048-bit minimum for RS256
  3. Set short expiration times — minutes to hours, not days
  4. Never store sensitive data in the payload — it is not encrypted
  5. Validate all claims — check exp, iss, aud on every request
  6. Rotate keys periodically — especially if any service is compromised
  7. Decode tokens locally — never use online tools for live tokens

Related Articles

Related Tool

Ready to use the Offline JWT Decoder (No Server Logs) tool? All execution is 100% local.

Open Offline JWT Decoder (No Server Logs)