JWT Tokens Explained: Header, Payload & Signature

JSON Web Tokens (JWTs) are the backbone of modern web authentication. If you have ever logged into a single-page application, used an OAuth-protected API, or worked with microservices, you have almost certainly handled JWTs. Despite their ubiquity, JWTs are frequently misunderstood — leading to security vulnerabilities that could have been avoided with a solid understanding of how they work.

Want to inspect a JWT right now? Paste it into our JWT Decoder to instantly see the header, payload, and signature — all decoded in your browser.

What Is a JWT?

A JSON Web Token is a compact, URL-safe string that represents claims (pieces of information) between two parties. It is defined in RFC 7519 and is pronounced "jot." JWTs are self-contained: the token itself carries all the information needed to verify the user's identity and permissions, without requiring a database lookup on every request.

A JWT looks like this:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

Three parts separated by dots. Each part has a specific purpose. Let us break them down.

The Three Parts of a JWT

1. Header

The header is a JSON object that describes the token type and the signing algorithm. It is Base64url-encoded to form the first part of the token:

// Encoded:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9

// Decoded:
{
  "alg": "HS256",
  "typ": "JWT"
}
  • alg — the signing algorithm. Common values: HS256 (HMAC-SHA256), RS256 (RSA-SHA256), ES256 (ECDSA-SHA256), none (unsigned, dangerous).
  • typ — the token type, always "JWT".

2. Payload (Claims)

The payload contains the claims — statements about the user and additional metadata. It is also Base64url-encoded:

// Encoded:
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0

// Decoded:
{
  "sub": "1234567890",
  "name": "John Doe",
  "admin": true,
  "iat": 1516239022
}

Claims fall into three categories:

Registered Claims (defined in RFC 7519, all optional but recommended):

  • iss (issuer) — who created the token (e.g., "auth.example.com")
  • sub (subject) — who the token is about (usually the user ID)
  • aud (audience) — who the token is intended for (e.g., "api.example.com")
  • exp (expiration) — Unix timestamp when the token expires
  • iat (issued at) — Unix timestamp when the token was created
  • nbf (not before) — token is invalid before this time
  • jti (JWT ID) — unique identifier for the token (useful for revocation)

Public Claims are defined in the IANA JSON Web Token Registry to avoid naming collisions between organizations. Examples include email, name, and picture.

Private Claims are custom claims agreed upon between the parties, like admin, role, or department.

3. Signature

The signature is what makes JWTs trustworthy. It ensures the token has not been tampered with since it was created. The signature is computed by taking the encoded header, encoded payload, a secret key, and the algorithm specified in the header:

// For HMAC-SHA256:
HMACSHA256(
  base64UrlEncode(header) + "." + base64UrlEncode(payload),
  secret
)

// For RSA-SHA256:
RSASHA256(
  base64UrlEncode(header) + "." + base64UrlEncode(payload),
  privateKey
)

When a server receives a JWT, it recalculates the signature using its secret key and compares it with the signature in the token. If they do not match, the token has been altered and is rejected.

HMAC vs. RSA Signing

Choosing the right algorithm depends on your architecture:

  • HMAC (HS256, HS384, HS512) — symmetric algorithm. The same secret key is used to both sign and verify the token. Simple and fast. Best for monolithic applications where only one server creates and validates tokens.
  • RSA (RS256, RS384, RS512) — asymmetric algorithm. A private key signs the token, and a public key verifies it. The public key can be shared freely. Best for microservices and distributed systems where many services need to verify tokens but only the auth server should create them.
  • ECDSA (ES256, ES384, ES512) — asymmetric like RSA but with smaller key sizes and faster signature generation. Increasingly popular for mobile and IoT applications.

When to Use JWTs

Authentication

The most common use case. After a user logs in, the server issues a JWT. The client includes the token in the Authorization header of subsequent requests:

Authorization: Bearer eyJhbGciOiJIUzI1NiIs...

The server verifies the signature and extracts the user's identity from the payload — no database query needed.

Authorization

JWTs can carry role and permission claims. A token with "role": "admin" lets API endpoints check permissions directly from the token without querying a permissions database on every request.

Information Exchange

Because JWTs are signed, the receiver can trust that the content has not been modified. This makes them useful for securely passing information between services in a microservices architecture.

Security Best Practices

JWTs are powerful but can be dangerous when misused. Follow these rules:

  • Always verify the signature — never trust a JWT without validating it. Use a well-tested library like jsonwebtoken (Node.js), PyJWT (Python), or java-jwt (Java).
  • Always check the exp claim — reject expired tokens. Clock skew of a few seconds is normal; most libraries allow a configurable leeway.
  • Validate iss and aud — ensure the token was issued by your auth server and intended for your application. This prevents token confusion attacks across different services.
  • Never accept "alg": "none" — the none algorithm means no signature. Attackers modify the header to "alg": "none" and strip the signature. Your library must reject unsigned tokens.
  • Keep tokens short-lived — access tokens should expire in 5-15 minutes. Use refresh tokens (stored securely, typically in HttpOnly cookies) for obtaining new access tokens.
  • Do not store sensitive data in the payload — the payload is not encrypted, just encoded. Anyone can decode it. Never include passwords, credit card numbers, or secrets.
  • Use HTTPS — JWTs transmitted over plain HTTP can be intercepted. Always use TLS.
  • Use strong secrets — for HMAC signing, use a cryptographically random secret of at least 256 bits. A short or predictable secret can be brute-forced.

Common Pitfalls

  • Storing too much in the token — every claim increases the token size, which is sent with every request. Keep payloads lean. Put detailed user data in a cache or database, not the JWT.
  • Not implementing token revocation — JWTs are valid until they expire. If a user logs out or an account is compromised, you cannot "invalidate" a JWT unless you maintain a server-side blocklist or use very short expiration times.
  • Algorithm confusion attacks — if your server accepts multiple algorithms, an attacker might switch from RSA to HMAC and use the public key as the HMAC secret. Always whitelist the expected algorithm on the server side.
  • Using JWTs as session storage — JWTs are not a replacement for server-side sessions in all cases. If you need instant revocation, session data that changes frequently, or tokens that exceed 8KB, traditional sessions may be simpler and safer.

Decode Your JWTs Now

Our JWT Decoder instantly splits any token into its header, payload, and signature. See the decoded JSON, verify the structure, and check the expiration — all in your browser. For related tasks, try the Base64 Encoder/Decoder, Hash Generator, or JSON Formatter.

Frequently Asked Questions

When a JWT's exp (expiration) claim is in the past, the server should reject it with a 401 Unauthorized response. The client then needs to obtain a new token, typically by using a refresh token to get a new access token without requiring the user to log in again. If the refresh token is also expired, the user must re-authenticate.
Yes. The header and payload of a JWT are only Base64url-encoded, not encrypted. Anyone can decode and read them. The secret key is only needed to verify the signature, which proves the token has not been tampered with. This is why you should never put sensitive data like passwords in a JWT payload.
HMAC (HS256/HS384/HS512) uses a single shared secret for both signing and verification. It is simpler and faster but requires both parties to know the secret. RSA (RS256/RS384/RS512) uses a public/private key pair: the private key signs the token, and the public key verifies it. RSA is preferred in distributed systems where you want services to verify tokens without having the signing key.
Access tokens should be short-lived, typically 5 to 15 minutes. This limits the damage window if a token is stolen. Use refresh tokens (valid for days or weeks, stored securely) to obtain new access tokens without requiring re-authentication. For highly sensitive operations, consider even shorter lifetimes or requiring re-authentication.
Neither option is perfect. localStorage is vulnerable to XSS attacks since any JavaScript on the page can read it. Cookies with HttpOnly and Secure flags prevent JavaScript access but are vulnerable to CSRF attacks. The recommended approach is HttpOnly, Secure, SameSite=Strict cookies for the token, combined with CSRF protection. Never store tokens in sessionStorage or regular cookies without HttpOnly.