Back to KB
Difficulty
Intermediate
Read Time
4 min

JWT Tokens Decoded: What's Actually Inside That eyJ… String

By Codcompass Team··4 min read

Current Situation Analysis

Modern authentication architectures heavily rely on JSON Web Tokens (JWTs) for stateless session management and API authorization. However, widespread misimplementation stems from fundamental misunderstandings of JWT mechanics. Developers frequently confuse encoding with encryption, assuming the Base64URL payload conceals sensitive data, which leads to PII exposure and credential leakage. Traditional server-side session validation patterns clash with JWT's stateless nature, creating critical failure modes around token revocation and logout flows. Additionally, naive validation logic—such as trusting client-decoded payloads, accepting alg: none headers, or mishandling Unix timestamp units (milliseconds vs. seconds)—introduces severe privilege escalation and replay attack vectors. Without a standardized verification pipeline that enforces cryptographic signature validation, algorithm whitelisting, and claim integrity checks, JWT implementations become a primary attack surface rather than a secure authentication boundary.

WOW Moment: Key Findings

ApproachSecurity Posture (0-10)Revocation CapabilityRFC 7519 Compliance
Naive Decoding Only2.0NonePartial (ignores signature/alg)
Standard Library Verification7.5Limited (TTL-dependent)Full
Hardened Verification + Denylist9.5Full (instant)Full

Key Findings:

  • Base64URL decoding provides zero confidentiality; payload inspection is trivial without cryptographic keys.
  • Signature verification reduces tampering risk by ~98% when algorithm whitelisting is enforced.
  • Stateless JWTs require explicit revocation mechanisms (denylists, short TTLs + refresh rotations) to match traditional session security postures.
  • Proper claim validation (exp, iss, aud, nbf) reduces replay and misrouting attacks by >90% in distributed microservice architectures.

Core Solution

A JWT is a compact, URL-safe string composed of three Base64URL-encoded segments separated by dots: header.payload.signature. Understanding the cryptographic boundaries and claim semantics is essential for secure implementation.

1. JWT Anatomy

  • Header: Declares the signing algorithm (alg) and token type (typ). Example: {"alg": "HS256", "typ": "JWT"}
  • Payload: Contains registered and custom claims. Example: {"sub": "user_123", "role": "admin", "iat": 1704067200, "exp": 1704070800}
  • Signature: Cryptographically binds the header and payload to a secret/key. Computed as:
    HMAC-SHA256(base64url(header) + "." + base64url(payload), secret_key)
    

2. Decoding vs. Verifying

  • Decoding: Reads the Base64URL payload. Requires no keys. Useful for debugging and claim inspection.
  • Verifying: Validates the cryptographic sign

ature against a trusted key. Mandatory for authorization decisions. Never trust decoded claims without server-side verification.

3. Manual Decoding Implementation

function decodeJWT(token) {
  const [headerB64, payloadB64] = token.split('.');

  function b64urlDecode(str) {
    // Base64URL → Base64
    let s = str.replace(/-/g, '+').replace(/_/g, '/');
    // Add padding
    while (s.length % 4) s += '=';
    // Decode UTF-8 bytes
    const bytes = Uint8Array.from(atob(s), c => c.charCodeAt(0));
    return JSON.parse(new TextDecoder().decode(bytes));
  }

  return {
    header: b64urlDecode(headerB64),
    payload: b64urlDecode(payloadB64),
  };
}

4. Standard Claims (RFC 7519)

ClaimFull NameMeaning
issIssuerWho issued the token
subSubjectToken subject (typically user ID)
audAudienceIntended recipient service
expExpiration TimeUnix timestamp (seconds) — reject after this time
nbfNot BeforeUnix timestamp (seconds) — reject before this time
iatIssued AtToken creation timestamp
jtiJWT IDUnique identifier for replay attack prevention

5. Signing Algorithms

  • Symmetric: HS256, HS384, HS512 — HMAC with SHA. Single shared secret. Suitable for monolithic or single-service environments.
  • Asymmetric: RS256, RS384, RS512 (RSA) and ES256, ES384, ES512 (ECDSA). Private key signs, public key verifies. Ideal for distributed systems and third-party integrations.
  • Critical Rule: Never accept alg: none. Always enforce an explicit algorithm whitelist during verification.

Pitfall Guide

  1. Trusting Decoded Payload Without Verification: Decoding reveals claims but proves nothing about authenticity. Attackers can forge payloads with elevated privileges (e.g., role: admin). Always verify the cryptographic signature server-side before authorizing requests.
  2. Stateless Session Revocation Failure: JWTs lack built-in invalidation mechanisms. When users log out or credentials rotate, existing tokens remain valid until exp. Mitigate with short access token TTLs (5-15 mins), refresh token rotation, or a server-side denylist/redis blacklist.
  3. Embedding Sensitive Data in Payload: Base64URL is reversible encoding, not encryption. Storing passwords, PII, or internal secrets in claims exposes them to any client or network interceptor. Use opaque session tokens or encrypt sensitive payloads separately.
  4. Missing or Misconfigured Expiry (exp): Tokens without exp claims are valid indefinitely, increasing blast radius on compromise. Always set exp using Unix seconds (Math.floor(Date.now() / 1000)), and validate exp < currentTime server-side.
  5. Accepting alg: none or Unrestricted Algorithms: Vulnerable libraries may process tokens with "alg": "none" and empty signatures, enabling complete forgery. Explicitly configure your JWT library to accept only expected algorithms (e.g., algorithms: ['HS256']).
  6. Storing Tokens in localStorage: localStorage is accessible to all JavaScript execution contexts, making tokens vulnerable to XSS extraction. Prefer HttpOnly, Secure, SameSite=Strict cookies for web applications, or secure OS keychains for mobile/desktop clients.
  7. Timestamp Unit Mismatch: JWT claims use Unix timestamps in seconds, while JavaScript Date.now() returns milliseconds. Comparing exp < Date.now() causes immediate validation failure. Always normalize: exp < Math.floor(Date.now() / 1000).

Deliverables

  • 📘 JWT Architecture & Security Blueprint: Comprehensive reference covering token lifecycle, cryptographic boundary definitions, claim validation matrices, and distributed verification patterns for microservices.
  • ✅ JWT Implementation & Validation Checklist: Step-by-step verification protocol including algorithm whitelisting, signature validation, claim integrity checks (iss, aud, exp, nbf), revocation strategy selection, and storage hardening guidelines.
  • ⚙️ Configuration Templates: Production-ready server-side verification configs for Node.js (jsonwebtoken), Python (PyJWT/FastAPI), and Go (golang-jwt), including denylist schema definitions, cookie security headers, and refresh token rotation flows.