HMAC in JWT Token Signing (HS256)

Explore how JWTs use HMAC-SHA256 (HS256) for symmetric signing. Understand when to choose HMAC-based JWTs over RSA, and the security trade-offs of shared secret signing.

API Security

Detailed Explanation

HMAC and JWT Signing (HS256/HS384/HS512)

JSON Web Tokens (JWTs) can be signed using either asymmetric algorithms (RS256, ES256) or symmetric HMAC algorithms (HS256, HS384, HS512). The "HS" prefix stands for HMAC with SHA, making HMAC a core component of the JWT ecosystem.

How HS256 Signing Works

A JWT consists of three Base64url-encoded parts separated by dots: header.payload.signature. For HS256:

  1. Header: {"alg": "HS256", "typ": "JWT"} → Base64url encoded
  2. Payload: Claims like {"sub": "user123", "exp": 1700000000} → Base64url encoded
  3. Signature: HMAC_SHA256(secret, base64url(header) + "." + base64url(payload)) → Base64url encoded

The signature input is the literal string header.payload (the dot-separated Base64url-encoded header and payload). The server verifies by recomputing this HMAC with the same secret.

HS256 vs RS256: When to Use Which

Factor HS256 (HMAC) RS256 (RSA)
Key type Shared secret Public/private key pair
Performance Very fast Slower (especially signing)
Key distribution Both parties need the secret Only public key needed to verify
Best for Single service / monolith Distributed systems / microservices
Risk Secret compromise = forge + verify Private key compromise = forge only

Security Considerations for HS256

Key management: The same key both signs and verifies. Every service that needs to verify tokens must have the secret, creating a wider attack surface. In microservices architectures, RS256 is often preferred because only the auth service needs the private key.

Algorithm confusion attacks: A well-known vulnerability occurs when a server accepts both HS256 and RS256. An attacker can take the public RSA key (which is public), use it as the HMAC secret to sign a token with HS256, and if the server verifies with the same key, the forged token passes verification. Always validate the alg header against an allowlist.

Secret strength: HS256 secrets must be at least 256 bits of random data. Using short passwords or predictable strings allows brute-force attacks against the secret. Use crypto.randomBytes(32) or equivalent.

Practical Recommendation

Use HS256 for simple, single-service applications where the same code signs and verifies. Use RS256 or ES256 for distributed systems where multiple services verify tokens but only one service issues them.

Use Case

HS256 JWT signing is used in single-service authentication systems, session management in monolithic applications, and internal service tokens where the issuer and verifier are the same system and key distribution is not a concern.

Try It — HMAC Generator

Open full tool