Skip to content

JWT Signing Algorithms — HS256, RS256, ES256 Explained with Examples

DodaTech Updated 2026-06-28 4 min read

In this tutorial, you will learn about JWT Signing Algorithms. We cover key concepts, practical examples, and best practices to help you master this topic.

JWT signing algorithms define how the signature is computed and verified, with symmetric (HS256) using a shared secret and asymmetric (RS256, ES256) using public-private key pairs.

What You'll Learn

The differences between HS256, RS256, and ES256, how to generate keys for each, when to use each algorithm, and security best practices.

Why It Matters

Algorithm choice affects security, performance, and key management. Using the wrong algorithm (e.g., HS256 in a multi-service architecture) creates security vulnerabilities. Understanding each algorithm helps you choose correctly.

Real-World Use

Auth0 defaults to RS256 for multi-service architectures. Firebase uses RS256. Internal Microservices might use HS256 for simplicity. Google uses ES256 for its low-latency requirements.

flowchart TD
    A["JWT Signing"] --> B["Symmetric\nHS256"]
    A --> C["Asymmetric\nRS256, ES256"]
    B --> D["Single secret\nSign + Verify"]
    C --> E["Private key: Sign\nPublic key: Verify"]
    B --> F["Simple, fast\n1 key to protect"]
    C --> G["Distributed verification\nPublic key is safe to share"]
    style A fill:#dbeafe,stroke:#2563eb
    style B fill:#fef3c7,stroke:#d97706
    style C fill:#dcfce7,stroke:#16a34a

Algorithm Comparison

Algorithm Type Key Size Speed Use Case
HS256 Symmetric (HMAC) 256+ bits Fastest Single service, internal
RS256 Asymmetric (RSA) 2048+ bits Slower sign, fast verify Distributed microservices
ES256 Asymmetric (ECDSA) 256 bits Fast, compact Mobile, IoT, performance

Code Example: HS256 (Symmetric)

import jwt
import datetime

# Single shared secret
SECRET = "my-very-secure-secret-at-least-32-chars"

# Sign
token = jwt.encode(
    {"sub": "user-123", "exp": datetime.datetime.utcnow() + datetime.timedelta(hours=1)},
    SECRET,
    algorithm="HS256"
)

# Verify (uses same secret)
decoded = jwt.decode(token, SECRET, algorithms=["HS256"])

Code Example: RS256 (Asymmetric)

from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.backends import default_backend
import jwt, datetime

# Generate RSA key pair
private_key = rsa.generate_private_key(
    public_exponent=65537,
    key_size=2048,
    backend=default_backend()
)

# Get public key
public_key = private_key.public_key()

# Sign with private key
token = jwt.encode(
    {"sub": "user-123"},
    private_key,
    algorithm="RS256"
)

# Verify with public key
decoded = jwt.decode(token, public_key, algorithms=["RS256"])

Code Example: ES256 (ECDSA)

from cryptography.hazmat.primitives.asymmetric import ec
import jwt, datetime

# Generate ECDSA key pair
private_key = ec.generate_private_key(
    ec.SECP256R1(),  # P-256 curve
    default_backend()
)

public_key = private_key.public_key()

# Sign
token = jwt.encode({"sub": "user-123"}, private_key, algorithm="ES256")

# Verify
decoded = jwt.decode(token, public_key, algorithms=["ES256"])

Expected token sizes:

HS256: ~200 bytes (token)
RS256: ~500 bytes (larger signature)
ES256: ~250 bytes (compact signature)

Common Mistakes

1. Using HS256 Across Multiple Services

Every service that verifies the token has the secret. If one service is compromised, all tokens can be forged. Use RS256 for Distributed Systems.

2. Short RSA Keys

RSA keys under 2048 bits are vulnerable to factoring. Use 2048+ bits for RS256.

3. Not Setting Algorithm Allowlist

Always specify algorithms=["HS256"] when decoding. Without it, an attacker could change the algorithm in the header (algorithm confusion attack).

4. Reusing Keys Across Environments

Use different keys for development, staging, and production. A compromised dev key should not affect production.

5. Hardcoding Private Keys

Private keys must be stored securely (HSM, secret manager, encrypted file). Never commit private keys to version control.

Practice Questions

  1. What is the difference between symmetric and asymmetric signing?
  2. When should you use RS256 instead of HS256?
  3. Why is ES256 faster than RS256?
  4. What key size is recommended for RS256?
  5. What is the algorithm confusion attack?

Answers:

  1. Symmetric (HS256) uses one shared secret for sign and verify. Asymmetric (RS256, ES256) uses a private key to sign and a public key to verify.
  2. RS256 when multiple services need to verify tokens without sharing a secret. Each service only needs the public key.
  3. ES256 uses elliptic curve cryptography which provides equivalent security to RSA with smaller keys and faster operations.
  4. At least 2048 bits. 4096 bits is recommended for high-security applications.
  5. An attacker changes the alg header from RS256 to HS256 and signs the token with the public key (which is public). The server, using the public key as an HMAC secret, accepts the forged token.

Challenge: Generate a key pair for RS256, sign a JWT with the private key, and verify it in a separate script using only the public key. Show that HS256 verification with the public key also works (demonstrating the algorithm confusion attack).

FAQ

Which algorithm is most secure?

All three are secure when used correctly. RS256 and ES256 are preferred for distributed systems. ES256 offers the best performance-to-security ratio.

Can I use multiple algorithms?

Yes, but configure each issuer with a specific algorithm. Validate the algorithm in the token header against an allowlist.

What is the 'none' algorithm?

The none algorithm means no signature. Some libraries (incorrectly) accept it. Never accept alg: none in production.

How do I rotate signing keys?

Use the kid (Key ID) header. Publish new JWKS with both old and new keys. Gradually transition clients to the new key.

Does algorithm choice affect token size?

Yes. RS256 produces larger signatures (~256 bytes) than HS256 (~32 bytes) or ES256 (~64 bytes). ES256 is most compact.

Mini Project

Build a JWT signing utility that supports HS256, RS256, and ES256. Generate keys for each, sign tokens, and verify them. Measure and compare token sizes and signing/verification speeds.

What's Next

Now learn about JWT Access Tokens — short-lived tokens for API authorization.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro