TOPIC #160Intermediate 10 min read

JWT Deep Dive: Structure, Signing, & Critical Pitfalls

CSD
CompleteSystemDesign Editorial
Report an issue
Key takeawayCore Architecture Summary

Master JSON Web Tokens: Base64URL anatomy, symmetric HS256 vs asymmetric RS256/ES256, JWKS key rotation, the "alg: none" vulnerability, RSA-to-HMAC key confusion attacks, and JWS vs JWE differences.

Key Glossary Concepts in this TopicAll Glossary Terms
Interactive Lab · 📜 JWT Tamper LabFull lab guide

JWT Anatomy & Signature Attack Lab

Forge tokens against three classic exploits, then harden the verifier's algorithm whitelist to kill them.

eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImF1dGgta2V5LTIwMjYtdjEifQ.eyJzdWIiOiJ1c3JfOTgxMjQiLCJyb2xlIjoidXNlciIsImlzcyI6Imh0dHBzOi8vYXV0aC5jb21wYW55LmNvbSIsImV4cCI6MTc3NDg4OTIwMH0.4731466262a2b64f4731466262a2b64f4731466262a2b64f4731466262a2b64f
Header (decoded — public!)
{"alg":"RS256","typ":"JWT","kid":"auth-key-2026-v1"}
Payload (decoded — NOT encrypted)
{"sub":"usr_98124","role":"user","iss":"https://auth.company.com","exp":1774889200}
VERIFIER ACCEPTED TOKEN247 B · role=user

Signature recomputed from header.payload matches — claims trusted.

Attack scenario

JWS ≠ encryption. Every byte above is public base64url — never put raw passwords or PII in claims (use JWE if confidentiality is required).

Defenses to state in interviews: whitelist algorithms, pin iss/aud, pick kid from JWKS only for the expected alg, prefer ES256/Ed25519 over RS256 for smaller keys at equal strength.

Signature here is a deterministic demo digest standing in for real RSA/HMAC math.

JWT Structure & Asymmetric JWKS Verification 📜

Deconstructing the 3-part Base64URL token and asymmetric signature verification across microservices.

JWT Structure & Asymmetric JWKS Verification 📜
100%
Touchpad: Pinch to zoom • Drag to pan
Rendering visual architecture flowchart...

01.Anatomy of a JSON Web Token (JWS)

A standard JSON Web Signature (JWS) token consists of three Base64URL-encoded JSON segments separated by literal periods (.): header.payload.signature.

1. Header (Metadata):

Defines the cryptographic algorithm and key metadata:

json
{
  "alg": "RS256",
  "typ": "JWT",
  "kid": "auth-key-2026-v1"
}
  • alg: The cryptographic signing algorithm (e.g., RS256 = RSA Signature with SHA-256; ES256 = ECDSA with P-256 and SHA-256; HS256 = HMAC-SHA256).
  • typ: Token type, typically "JWT".
  • kid: Key Identifier used by the verifying service to select the correct public key from a JWKS set.

2. Payload (Claims):

Contains statements about the subject entity and contextual metadata:

  • Registered Claims (RFC 7519 standard):
    • iss (Issuer): Who created and signed the token (e.g., https://auth.company.com/).
    • sub (Subject): Unique principal ID (e.g., usr_981442).
    • aud (Audience): Who the token is intended for (e.g., https://api.company.com/billing).
    • exp (Expiration Time): Unix epoch timestamp after which the token must be rejected.
    • nbf (Not Before): Unix epoch timestamp before which the token is invalid.
    • iat (Issued At): Unix epoch timestamp of token generation.
    • jti (JWT ID): Unique identifier for the token (used to detect replay attacks).
  • Custom / Application Claims: Arbitrary business data (e.g., roles: ["admin", "billing_manager"], tenant_id: "acme_corp").

3. Signature:

Guarantees integrity and authenticity. For RS256:

Signature = Sign_{PrivateKey}(Base64URL(Header) + "." + Base64URL(Payload))

02.Symmetric (HS256) vs Asymmetric (RS256 / ES256) Signing

Choosing the right signing algorithm is the single most critical architectural decision when designing JWT systems:

Symmetric (HMAC-SHA256 / HS256):

  • Mechanism: Uses a single shared symmetric secret key (e.g., a 256-bit random hex string) for both signing and verifying.
  • The Microservice Danger: If 50 microservices need to verify user tokens, all 50 services must possess the shared secret. If a single low-security microservice is compromised, the attacker extracts the secret and can forge valid tokens for any user or administrator across the entire ecosystem.

Asymmetric (RS256 / ES256 / Ed25519):

  • Mechanism: Uses a public/private keypair.
    • Private Key: Held exclusively by the centralized Identity Provider (Auth0, Okta, internal Auth Service). Only the IdP can sign tokens.
    • Public Key: Published openly via a JSON Web Key Set (JWKS) endpoint (e.g., https://auth.example.com/.well-known/jwks.json).
  • Zero Leakage Risk: Downstream microservices only download the public key. Even if an attacker compromises a microservice, they cannot forge signatures.
  • Modern Recommendation: Prefer ES256 (ECDSA) or Ed25519 over RS256 for faster computation (< 0.1ms) and smaller key sizes (256 bits vs 2048/4096 bits for equivalent cryptographic strength).

03.Critical JWT Security Pitfalls & Exploits

Numerous high-severity CVEs in major JWT libraries stem from improper signature validation logic:

1. The "alg": "none" Vulnerability (CVE-2015-9235):

The JWT specification allows an algorithm header value of "none" for unsecure tokens. Attackers strip the signature, change "alg": "RS256" to "none", alter the payload to "role": "admin", and submit the token. Vulnerable libraries accept the forged payload without checking the signature.

  • Defense: Explicitly configure JWT verification libraries to whitelist allowed algorithms: algorithms: ['RS256', 'ES256'] and reject none.

2. The RSA-to-HMAC Key Confusion Attack (CVE-2016-5431):

If an application supports both RS256 and HS256, an attacker takes the server's public RSA key (which is publicly available on the web) and uses it as the HMAC secret to sign a forged token with "alg": "HS256". If the backend parser uses a generic verify function that accepts any algorithm indicated in the token header, it verifies the signature using the RSA public key string with HMAC, which matches and passes validation!

  • Defense: Never determine the verification algorithm from the incoming token's unverified alg header. Hardcode or strictly enforce the expected algorithm in the verifier.

3. JWS vs JWE (Signing vs Encryption):

  • JWS (Signed JWT): Encoded in plaintext Base64URL. Anyone who intercepts the token can read all payload fields. Never store raw passwords, social security numbers, or sensitive API secrets in JWT claims.
  • JWE (Encrypted JWT): Encrypts the payload so that only holders of the decryption key can read the claims. Used when claims contain sensitive personal data.

04.Production TypeScript Verification with JWKS Caching

Below is a robust Node.js implementation using jwks-rsa and jsonwebtoken that securely fetches and caches public keys while guarding against known vulnerabilities:

typescript
import jwt, { JwtHeader, SigningKeyCallback } from 'jsonwebtoken';
import jwksClient from 'jwks-rsa';

// Configure secure JWKS client with in-memory caching & rate-limiting
const client = jwksClient({
  jwksUri: 'https://auth.company.com/.well-known/jwks.json',
  cache: true,
  cacheMaxEntries: 10,
  cacheMaxAge: 60 * 60 * 1000, // 1 hour TTL
  rateLimit: true,
  jwksRequestsPerMinute: 10 // Prevent DoS on JWKS endpoint
});

function getKey(header: JwtHeader, callback: SigningKeyCallback): void {
  if (!header.kid) {
    return callback(new Error('Missing kid (Key ID) header in JWT'));
  }

  client.getSigningKey(header.kid, (err, key) => {
    if (err || !key) {
      return callback(err || new Error('Signing key not found in JWKS'));
    }
    const signingKey = key.getPublicKey();
    callback(null, signingKey);
  });
}

export interface ValidatedUserClaims {
  sub: string;
  role: string;
  tenantId: string;
}

export function verifyUserToken(token: string): Promise<ValidatedUserClaims> {
  return new Promise((resolve, reject) => {
    jwt.verify(
      token,
      getKey,
      {
        // DEFENSE: Strictly whitelist expected algorithms (prevents "none" and key confusion)
        algorithms: ['RS256'],
        issuer: 'https://auth.company.com/',
        audience: 'https://api.company.com/'
      },
      (err, decoded) => {
        if (err) {
          return reject(new Error(`Token verification failed: ${err.message}`));
        }
        resolve(decoded as ValidatedUserClaims);
      }
    );
  });
}

Architectural Trade-offs & Production Realities

Architectural Advantages

  • RS256/ES256 with JWKS enables seamless, decentralized verification across polyglot microservices without sharing secrets
  • Standardized claims (iss, sub, aud, exp, iat) simplify cross-organizational federation
  • Public key rotation via JWKS requires zero deployment downtime on downstream services

Trade-offs & Constraints

  • Payload claims are visible to anyone in plaintext; sensitive PII must not be stored in standard JWS tokens
  • Misconfigured verification libraries that dynamically trust the "alg" header are susceptible to critical exploits (alg: none, key confusion)
  • JWT tokens are bulky compared to 32-byte opaque tokens, increasing HTTP header overhead on every request
Production Implementation in Big Tech
GitHub Actions & AWS IAM• OIDC Workload Identity Federation

When a GitHub Actions workflow deploys to AWS, GitHub generates a short-lived (10-minute) RS256 JWT. AWS IAM verifies the token against GitHub's public JWKS endpoint (`https://token.actions.githubusercontent.com/.well-known/jwks.json`) and exchanges it for temporary AWS STS credentials, completely eliminating hardcoded AWS secret keys from GitHub repositories.

Staff+ Engineering Takeaways

  • JWT consists of Header, Payload, and Signature in Base64URL encoding.
  • Always use asymmetric algorithms (RS256 / ES256) for microservice ecosystems.
  • Strictly whitelist verification algorithms to eliminate "alg: none" and RSA-to-HMAC key confusion attacks.
  • Never store sensitive confidential secrets in standard JWS claims; they are readable by anyone.

Topic Knowledge Check

Exercise 1 of 2 • Test your architectural comprehension.

Exercise 1 of 20 answered
1

What is the root vulnerability underlying the RSA-to-HMAC "Key Confusion" attack in JWT validation libraries?

Rate This Architecture ChapterFeedback & Rating

How clear and actionable was this distributed systems breakdown?

Interactive Engineering Workbenches: