By AndyPublished
HS256 vs RS256: When to Use Symmetric vs Asymmetric JWT Signing
The Fundamental Difference
HS256 is a symmetric algorithm. It uses a single shared secret for both signing and verification. Any party with the secret can sign and verify tokens.
RS256 is an asymmetric algorithm. It uses a private key for signing and a public key for verification. Only the party with the private key can sign tokens, but anyone with the public key can verify them, without being able to forge new tokens.
// HS256: one secret, used for both sign(payload, secret) → token verify(token, secret) → valid/invalid // RS256: separate keys for sign vs verify sign(payload, private_key) → token verify(token, public_key) → valid/invalid
HS256: HMAC-SHA256
How it works
HMAC-SHA256 computes a keyed hash of the signing input (base64url(header) + "." + base64url(payload)) using the shared secret. The output is used as the JWT signature. Verification re-computes the HMAC and compares it to the token's signature using a constant-time comparison.
When to use HS256
- ·Simple architectures with a single auth server and a single API service that are both under your control and share the same trust boundary
- ·Environments where distributing and managing a public key infrastructure adds complexity that isn't justified by the scale
- ·Internal tools or development environments where the secret can be tightly controlled
HS256 limitations
- ·Secret distribution problem: The shared secret must be securely distributed to every service that verifies tokens. More services = more exposure.
- ·No separation of signing authority: A verifier is also a potential forger. This is acceptable in a monolithic app but dangerous in a multi-team microservices environment.
- ·Rotation complexity: Rotating the secret requires coordinating the update across all services simultaneously or implementing a dual-secret overlap period.
- ·Low-entropy secret risk: An HS256 secret is only as strong as the entropy it contains. Short or predictable secrets (common passwords, UUIDs, base64 of a short string) are vulnerable to offline brute-force attacks against captured tokens. Use at least 32 bytes of cryptographically random data.
RS256: RSA-SHA256
How it works
The auth server uses a 2048-bit (or larger) RSA private key to sign the token with PKCS#1 v1.5 padding. API services verify the token using the corresponding RSA public key. The public key can be distributed via a JWKS endpoint without security risk.
When to use RS256
- ·Architectures with multiple independent services that need to verify tokens, each gets the public key but cannot forge tokens
- ·Any system where the token issuer (auth server) and the token consumers (APIs) are operated by different teams or organizations
- ·When you want to publish your public keys openly via a JWKS endpoint for third-party integrations or open-source SDKs
- ·Production systems where the principle of least privilege applies, services should not have access to capabilities they don't need
ES256: ECDSA as an Alternative
ES256 (ECDSA with P-256 and SHA-256) provides the same separation of signing and verification as RS256, but with much smaller keys and signatures. An ES256 private key is 256 bits; an RS256 key is typically 2048–4096 bits.
- ·Smaller signatures reduce JWT size and HTTP header overhead
- ·Faster verification on constrained hardware (IoT, edge nodes)
- ·Equivalent security to RS256 with much smaller keys
- ·Slightly more complex to implement correctly, use a well-tested library
PS256: RSA-PSS as the Modern Alternative to RS256
PS256 (RSA-PSS with SHA-256) is the successor to RS256. Both use RSA key pairs, but they differ in the padding scheme applied before signing:
- ·RS256 uses PKCS#1 v1.5 padding: deterministic, well-understood, but the padding scheme has theoretical weaknesses (Bleichenbacher attacks) and lacks a tight security proof in the standard cryptographic sense.
- ·PS256 uses PSS (Probabilistic Signature Scheme) padding: randomised (each signature of the same input produces a different output), and provably secure in the random oracle model. RFC 7518 notes that RSA-PSS is preferable to PKCS#1 v1.5 for new implementations.
In practice, both RS256 and PS256 are secure with 2048+ bit keys. The choice matters more for compliance (some standards now mandate PSS) than for immediate attack surface. If you are starting a new system and require RSA, use PS256. If you are operating an existing RS256 system, migration is low-priority unless your threat model or compliance requirements demand it.
Real-World Algorithm Choices by Platform
Major identity providers and cloud platforms have made different default algorithm choices:
| Platform | Default algorithm | Notes |
|---|---|---|
| Auth0 | RS256 | Recommended default; HS256 available for legacy |
| Okta | RS256 | Keys published at /oauth2/v1/keys JWKS endpoint |
| AWS Cognito | RS256 | Keys at cognito-idp.<region>.amazonaws.com/<pool>/.well-known/jwks.json |
| Google (OAuth2 / Firebase) | RS256 | Keys at accounts.google.com/.well-known/openid-configuration |
| Azure AD / Entra ID | RS256 | Supports PS256 for newer app registrations |
| Keycloak | RS256 | Configurable; ES256 and PS256 available |
| Custom HS256 | HS256 | Typical for internal monolith, single shared secret |
If you integrate with a third-party identity provider, you have no choice, use whatever algorithm the provider issues. The choice between HS256 and RS256 is relevant only when you are building and operating your own token issuer.
Side-by-Side Comparison
| Property | HS256 | RS256 | ES256 |
|---|---|---|---|
| Algorithm type | Symmetric | Asymmetric | Asymmetric |
| Key for signing | Shared secret | RSA private key | EC private key |
| Key for verification | Same shared secret | RSA public key | EC public key |
| Key size | ≥ 32 bytes | 2048–4096 bits | 256 bits |
| Can verifier forge tokens? | Yes | No | No |
| JWKS support | No (key is secret) | Yes | Yes |
| Signature size | 32 bytes (HS256) | 256–512 bytes | 64 bytes |
| Best for | Single-service apps | Multi-service, enterprise | Performance-sensitive |
Migrating from HS256 to RS256
If you're upgrading an existing HS256 system to RS256:
- ·Generate an RSA or EC key pair in your auth service
- ·Publish the public key via a JWKS endpoint at a predictable URL
- ·Update all verifying services to fetch and cache the JWKS
- ·Deploy a transition period where both algorithms are accepted
- ·Once all existing HS256 tokens have expired, remove the old verification path
- ·Revoke and destroy the HS256 shared secret