HS256 vs RS256 — What Changes When Decoding?
Understand differences between symmetric and asymmetric JWT algorithms and what you can infer at decode time.
At decode time, you can read alg and kid from the header. Understanding why HS256 and RS256 differ—and how to verify each correctly—prevents security vulnerabilities and helps you debug authentication failures.
Why algorithms matter
The alg field in the JWT header tells you which cryptographic algorithm was used to sign the token. This matters because:
- Different algorithms require different keys - HS256 needs a shared secret, RS256 needs a public/private key pair
- Security properties differ - Symmetric vs asymmetric cryptography have different trade-offs
- Verification process differs - You can't verify an RS256 token with an HS256 secret
HS256 vs RS256: fundamental differences
HS256 (HMAC with SHA-256) - Symmetric
How it works:
- Uses a single shared secret that both signs and verifies tokens
- Same secret on both issuer and verifier sides
- Fast computation, simple implementation
Why it's used:
- Single-tenant applications
- Internal microservices with shared secrets
- High-performance scenarios where speed matters
Security considerations:
- Secret must be distributed securely to all verifiers
- If secret leaks, attacker can forge tokens
- Key rotation requires updating all services simultaneously
RS256 (RSA Signature with SHA-256) - Asymmetric
How it works:
- Private key signs tokens (only issuer has this)
- Public key verifies tokens (can be distributed widely)
- Public key can be fetched from JWKS endpoint
Why it's used:
- Multi-tenant SaaS applications
- Public APIs where verifiers can't share secrets
- Scenarios requiring key rotation without service restarts
Security considerations:
- Public key distribution is safer (can't forge tokens with public key)
- Key rotation via JWKS without code changes
- More complex implementation but better for distributed systems
What decoding reveals
When you decode a JWT header, you see:
{
"alg": "RS256",
"kid": "abc123",
"typ": "JWT"
}
alg field:
- Shows which algorithm was used
- Critical: Must match your application's expected algorithm
- Never auto-accept tokens with unexpected algorithms (algorithm confusion attack)
kid field (Key ID):
- Identifies which key from JWKS should verify this token
- Essential for key rotation scenarios
- Only present for RS256/ES256 (asymmetric algorithms)
Use our JWT Encoder/Decoder to quickly inspect the header and see which algorithm a token uses.
Verification differences explained
HS256 verification
Why it's simple: You already have the secret, so verification is straightforward—just use the same secret that signed it.
How to verify:
const jwt = require('jsonwebtoken');
// Verify with shared secret
const decoded = jwt.verify(token, process.env.JWT_SECRET, {
algorithms: ['HS256'], // Pin algorithm - critical!
audience: 'your-app-id',
issuer: 'https://your-issuer.com'
});
console.log('User:', decoded.sub);
Common mistakes:
- Not pinning algorithms (allows algorithm confusion attacks)
- Using wrong secret (dev vs prod environments)
- Not validating
audandissclaims
RS256 verification
Why it's more complex:
You need to fetch the public key from the issuer's JWKS endpoint, select the right key by kid, convert it to PEM format, then verify.
How to verify:
const jwt = require('jsonwebtoken');
const jwksClient = require('jwks-rsa');
// Decode header to get kid
const [headerSegment] = token.split('.');
const header = JSON.parse(
Buffer.from(headerSegment, 'base64url').toString()
);
// Setup JWKS client
const client = jwksClient({
jwksUri: `${issuer}/.well-known/jwks.json`,
cache: true,
cacheMaxAge: 86400000 // 24 hours
});
// Get signing key
const key = await client.getSigningKey(header.kid);
const publicKey = key.getPublicKey();
// Verify token
const decoded = jwt.verify(token, publicKey, {
algorithms: ['RS256'], // Pin algorithm
audience: 'your-app-id',
issuer: issuer
});
Why JWKS is needed:
- Issuers rotate keys periodically for security
- Multiple keys can be active simultaneously (old tokens still valid)
kidtells you which key to use from the JWKS set
Real-world scenarios
Scenario 1: Algorithm mismatch error
Problem: Token decodes fine but verification fails with "invalid signature"
Why it happens:
- Token was signed with RS256 but you're verifying with HS256 secret
- Or vice versa
How to fix:
- Decode the header to see
algfield using JWT Encoder/Decoder - Match your verification code to the algorithm in the header
- For RS256, ensure you're fetching JWKS and using public key
- For HS256, ensure you're using the correct shared secret
Scenario 2: Key rotation failure
Problem: Tokens that worked yesterday now fail verification
Why it happens:
- Issuer rotated keys and removed old key from JWKS
- Your JWKS cache is stale
- Token signed with old key but JWKS only has new key
How to fix:
// Refresh JWKS on verification failure
let decoded;
try {
decoded = jwt.verify(token, cachedPublicKey, options);
} catch (error) {
if (error.name === 'JsonWebTokenError') {
// Refresh JWKS and retry
await client.getSigningKey(header.kid, (err, key) => {
if (err) throw err;
const freshPublicKey = key.getPublicKey();
decoded = jwt.verify(token, freshPublicKey, options);
});
} else {
throw error;
}
}
Scenario 3: Multi-tenant application
Problem: Need to verify tokens from multiple issuers
Why RS256 helps:
- Each tenant can have their own JWKS endpoint
- Public keys can be fetched independently
- No shared secrets to manage
How to implement:
// Determine issuer from token
const { iss } = jwt.decode(token, { complete: false });
// Get JWKS client for this issuer
const client = getJwksClientForIssuer(iss);
// Verify with issuer-specific key
const key = await client.getSigningKey(header.kid);
const decoded = jwt.verify(token, key.getPublicKey(), {
algorithms: ['RS256'],
issuer: iss
});
Security best practices
1. Always pin algorithms
Never do this:
// BAD - accepts any algorithm
jwt.verify(token, secret);
Always do this:
// GOOD - pins expected algorithm
jwt.verify(token, secret, { algorithms: ['HS256'] });
Why: Prevents algorithm confusion attacks where an attacker creates a token with alg: none or a weaker algorithm.
2. Validate all claims
Don't just verify the signature—check claims too:
jwt.verify(token, key, {
algorithms: ['RS256'],
audience: 'your-app-id', // Must match
issuer: 'https://issuer.com', // Must match exactly
clockTolerance: 60 // Allow 60s clock skew
});
3. Handle key rotation gracefully
// Cache JWKS but refresh on failure
const client = jwksClient({
jwksUri: jwksUrl,
cache: true,
cacheMaxAge: 3600000, // 1 hour
rateLimit: true,
jwksRequestsPerMinute: 5
});
Choosing the right algorithm
Use HS256 when:
- Single application or trusted microservices
- Performance is critical
- You can securely distribute secrets
- Key rotation can be coordinated across services
Use RS256 when:
- Multi-tenant SaaS applications
- Public APIs with many verifiers
- Need key rotation without downtime
- Verifiers can't share secrets securely
Debugging tips
- Decode first - Use JWT Encoder/Decoder to see
algandkidbefore debugging verification - Check algorithm match - Ensure your verification code uses the same algorithm as the token header
- Verify JWKS access - For RS256, ensure you can fetch
/.well-known/jwks.jsonfrom the issuer - Check key selection - For RS256, verify
kidin header matches a key in JWKS - Validate claims - Signature verification can pass but claims might be invalid (wrong
aud, expiredexp)
Next steps
- Decode a token with our JWT Encoder/Decoder to see the
algfield - Learn about JWKS and key rotation for RS256
- Understand safe decoding practices before verification
- Read our troubleshooting guide for common errors
Try JWT Encoder/Decoder Now
Ready to put this into practice? Use our free JWT Encoder/Decoder tool. It works entirely in your browser with no signup required.
Launch JWT Encoder/DecoderFrequently Asked Questions
Q Can I know the algorithm from the header?
Yes. The header alg field indicates HS256, RS256, etc., but validation must match the expected algorithm server-side.
Related Articles
JWT Tokens Explained - Complete Guide to JSON Web Tokens
Learn everything about JWT tokens, how they work, when to use them, and best practices for secure implementation in your applications.
JWKS Key Rotation & 'kid' Errors: Complete Guide + Online Decoder Tool
Stop JWKS validation headaches. Learn how key rotation and the 'kid' claim work, and use our FREE, expert online tool to decode, verify, and troubleshoot your JWKS tokens fast.
How to Decode JWT Safely (Header, Payload, Signature)
Learn how to safely decode JWTs, what each part means, and where security risks arise.