Skip to main content
JWT

JSON Web Token

Active

JSON Web Token (JWT) is a compact, URL-safe method for representing claims between two parties, defined by RFC 7519. A JWT is a Base64URL-encoded JSON header and payload separated by dots, followed by a cryptographic signature. JWTs are self-contained – the recipient can verify them without calling the issuer. They are the standard token format for OAuth 2.0 access tokens and OpenID Connect ID Tokens.

JWTRFC 7519AuthBearer TokenOIDCOAuth2015
Algorithms

In one line

JWT (RFC 7519, 2015) is a Base64URL-encoded, dot-separated token: header.payload.signature. The header declares the algorithm (alg) and token type. The payload carries claims: registered (iss, sub, aud, exp, iat, jti), public, and private. The signature is produced with a secret (HMAC) or private key (RSA, EC). Recipients verify the signature and validate exp, iss, aud before trusting any claims. JWTs are used as OAuth 2.0 access tokens and OIDC ID Tokens.

Quick Reference

FieldSizeDescription
Structureheader.payload.sigThree Base64URL segments separated by dots. header and payload are JSON objects. signature is the HMAC or RSA/EC signature over the encoded header and payload.
Header claimsalg, typ, kidalg: signing algorithm (RS256, HS256, ES256). typ: token type, usually JWT. kid: key ID, used to select the correct verification key from a JWKS.
Registered claims7 definediss (issuer), sub (subject), aud (audience), exp (expiration), nbf (not before), iat (issued at), jti (JWT ID). All optional by RFC but exp, iss, aud are required by OIDC.
expUnix timestampExpiration time. Token MUST be rejected after this time. Allow ≤60 seconds clock skew. Always validate exp.
audstring or arrayIntended audience. Recipient MUST verify their identifier is in aud. Prevents a token issued for service A from being used at service B.
SigningHMAC or asymmetricSymmetric: HS256/HS384/HS512 (shared secret). Asymmetric: RS256/RS384/RS512 (RSA), ES256/ES384/ES512 (ECDSA), PS256/PS384/PS512 (RSASSA-PSS).
JWKS/.well-known/jwks.jsonJSON Web Key Set endpoint. Publishes the issuer's public keys for offline JWT verification. Clients cache JWKS and re-fetch on cache miss for unknown kid.
alg:noneFORBIDDENThe none algorithm produces an unsigned JWT. MUST be rejected by all servers. A classic attack: change the alg header to none and strip the signature.

Key Characteristics

Self-contained

JWTs carry all needed claims. The recipient verifies the signature and reads the payload without calling the issuer. No database lookup required. This is both the main benefit and the main risk – revocation is hard.

Signature verification

Verification requires the issuer's public key (asymmetric) or shared secret (HMAC). Always verify the signature before reading any claims. Accepting an unsigned or incorrectly signed JWT is a critical security flaw.

Not encrypted by default

A JWT (JWS) is signed but not encrypted. The payload is Base64URL-encoded, not encrypted – anyone can decode and read it. Never put passwords, PII, or secrets in a JWT payload unless using JWE (RFC 7516).

Revocation is hard

Self-contained JWTs cannot be revoked without a token denylist. Once issued, a JWT is valid until exp. Keep access token lifetimes short (15–60 minutes). Use refresh tokens with rotation for longer sessions.

Message Format

Request
http
# JWT structure (decoded)
# Format: Base64URL(header).Base64URL(payload).signature

# Header
{
  "alg": "RS256",        // signing algorithm
  "typ": "JWT",          // token type
  "kid": "key-2026-01"   // key ID for JWKS lookup
}

# Payload (claims)
{
  "iss": "https://auth.example.com",       // issuer
  "sub": "usr_abc123",                     // subject (user ID)
  "aud": "https://api.example.com",        // audience
  "exp": 1721912400,                       // expires at (Unix timestamp)
  "iat": 1721908800,                       // issued at
  "jti": "f47ac10b-58cc-4372-a567-0e02b2c3d479",  // JWT ID (unique)
  "email": "[email protected]",
  "scope": "read:profile write:orders"
}

# Signature
# RSASSA-PKCS1-v1_5(SHA-256, private_key,
#   Base64URL(header) + "." + Base64URL(payload))
Response
http
# Full JWT token (encoded)
eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImtleS0yMDI2LTAxIn0
.eyJpc3MiOiJodHRwczovL2F1dGguZXhhbXBsZS5jb20iLCJzdWIiOiJ1c3JfYWJjMTIzIiwiYXVkIjoiaHR0cHM6Ly9hcGkuZXhhbXBsZS5jb20iLCJleHAiOjE3MjE5MTI0MDAsImlhdCI6MTcyMTkwODgwMH0
.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

# Use as Bearer token
Authorization: Bearer eyJhbGciOiJSUzI1NiIs...

# Validation checklist (RFC 7519 §7.2 + RFC 8725):
# 1. Verify signature using issuer's public key (from JWKS)
# 2. Verify alg matches expected algorithm (never accept alg:none)
# 3. Verify exp > current time (allow ≤60s clock skew)
# 4. Verify iss matches expected issuer
# 5. Verify aud contains your service's identifier
# 6. Verify nbf ≤ current time (if present)
# 7. Check jti against denylist (if revocation is needed)

Implementations

linuxsince jsonwebtoken (Node.js), PyJWT (Python), golang-jwt (Go), jsonwebtoken (Rust: jsonwebtoken crate), java-jwt (Auth0 Java)available
macossince Same as Linux. jwt.io debugger in browser.available
windowssince System.IdentityModel.Tokens.Jwt (.NET), jsonwebtoken (Node.js), PyJWT.available
iossince JWTDecode (Auth0 Swift), swift-jwt (IBM).available
androidsince java-jwt (Auth0), jjwt (Java/Kotlin).available