taptools/blog/HS256 vs RS256
JWTMay 15, 2026 · 7 min read

HS256 vs RS256 — Which JWT Algorithm Should You Use?

Choosing the wrong JWT signing algorithm is a common security mistake. This guide explains the exact differences between HS256 and RS256 and when to use each one.

The short answer

Use HS256 when:

  • → Single server/service
  • → You control both issuer and verifier
  • → Simple monolithic application
  • → Internal microservices (same team)

Use RS256 when:

  • → Multiple services verify tokens
  • → Third party services need to verify
  • → Public API with external consumers
  • → Microservices architecture

How HS256 works

HS256 stands for HMAC with SHA-256. It uses a single shared secret key to both sign and verify tokens. This means the same secret must be available to every service that needs to verify the token.

// HS256 — same secret for signing and verifying
const secret = "my-super-secret-key"

// Sign
const token = jwt.sign(payload, secret, { 
  algorithm: 'HS256' 
})

// Verify (requires the SAME secret)
const decoded = jwt.verify(token, secret)

// Problem: every service that verifies
// needs access to the secret key!

⚠️ Security risk: If multiple services share the same HS256 secret, any compromised service can create valid tokens — not just verify them.

How RS256 works

RS256 stands for RSA Signature with SHA-256. It uses asymmetric cryptography — a private key to sign tokens and a public key to verify them. Only the private key can create valid tokens. The public key can only verify.

// RS256 — different keys for signing and verifying
const privateKey = fs.readFileSync('private.pem')
const publicKey  = fs.readFileSync('public.pem')

// Sign — only auth server has private key
const token = jwt.sign(payload, privateKey, { 
  algorithm: 'RS256' 
})

// Verify — any service can have the public key
const decoded = jwt.verify(token, publicKey)

// Public key can verify but CANNOT create tokens
// Much safer for distributed systems!

Side by side comparison

FeatureHS256RS256
Algorithm typeSymmetric (HMAC)Asymmetric (RSA)
Keys required1 shared secretPrivate + public key pair
Who can signAnyone with secretOnly private key holder
Who can verifyAnyone with secretAnyone with public key
PerformanceFasterSlightly slower
Key distributionSecret must stay secretPublic key can be shared freely
Best forSingle serviceDistributed systems
Used bySimple APIsAuth0, Firebase, Okta

Real world examples

Firebase uses RS256

Firebase Auth tokens are signed with RS256. Google publishes the public keys at a well-known URL so any service can verify Firebase tokens without needing Google's private key.

// Firebase public keys are published here
https://www.googleapis.com/robot/v1/metadata/x509/
  securetoken@system.gserviceaccount.com

// Your backend fetches these to verify tokens
// No shared secret needed

Supabase uses HS256

Supabase uses HS256 with your project's JWT secret. This works well because your backend and Supabase share the same secret. If you expose your Supabase JWT secret anyone can forge tokens.

How to check which algorithm your token uses

The algorithm is stored in the JWT header — the first part of the token. You can see it instantly using our JWT Decoder.

// JWT header (decoded)
{
  "alg": "RS256",  ← algorithm used
  "typ": "JWT",
  "kid": "abc123"  ← key ID (RS256 only)
}

// For HS256 tokens
{
  "alg": "HS256",
  "typ": "JWT"
}

Check your JWT algorithm instantly

Paste your JWT token to see the algorithm, header claims and payload.

Open JWT Decoder →