JWT · June 20, 2026 · 9 min

How JWT Works: Structure, Security, and Decoding

Understand JSON Web Tokens — header, payload, signature — and how to decode them safely.

What Is a JWT?

A JSON Web Token (JWT) is a compact, URL-safe string format for representing claims between two parties. Defined in RFC 7519, JWTs are widely used for authentication and authorization in REST APIs, single sign-on systems, and microservice architectures. A JWT carries information about the user or session in a self-contained package that services can verify without querying a central database on every request.

Unlike opaque session tokens that map to server-side state, JWTs embed claims directly in the token itself. This stateless design scales horizontally — any server with the verification key can validate the token. The trade-off is that revoking a JWT before expiration requires additional infrastructure (token blocklists, short expiration times, or refresh token rotation).

JWTs are not encrypted by default — they are signed (or sometimes only encoded). Anyone can decode the header and payload to read the claims. Never store passwords, credit card numbers, or other secrets in a JWT payload. Use the JWT Decoder to inspect tokens during development; all processing happens locally in your browser.

JWT Structure: Header, Payload, Signature

A JWT consists of three parts separated by dots: `header.payload.signature`. Each part is Base64URL-encoded, which uses URL-safe characters (replacing `+` with `-` and `/` with `_`, and omitting padding `=`). The header typically contains `{"alg": "HS256", "typ": "JWT"}`, specifying the signing algorithm and token type.

The payload contains claims — statements about the subject and metadata. Standard registered claims include `iss` (issuer), `sub` (subject), `aud` (audience), `exp` (expiration time), `iat` (issued at), and `nbf` (not before). Custom claims carry application-specific data like user roles, permissions, or tenant IDs.

The signature is created by signing the encoded header and payload with a secret (for HMAC algorithms like HS256) or a private key (for RSA/ECDSA algorithms like RS256). Recipients verify the signature using the corresponding secret or public key. If the signature does not match, the token has been tampered with.

Decoding vs Verifying

Decoding a JWT means Base64URL-decoding the header and payload to read the JSON contents. This requires no secret and can be done by anyone — including attackers. The JWT Decoder formats the decoded header and payload as readable JSON and highlights expiration status.

Verifying a JWT means checking that the signature is valid using the correct key and that claims like `exp` have not expired. Verification must happen server-side in production. Client-side verification is meaningless because a malicious client can skip it entirely.

Use the Base64 Decode tool if you need to inspect individual Base64-encoded segments outside of a full JWT context. JWT uses Base64URL encoding, which is a variant of standard Base64 — the JWT Decoder handles this conversion automatically.

Signing Algorithms

HMAC algorithms (HS256, HS384, HS512) use a shared secret for both signing and verification. They are simple to implement but require all services to know the same secret, which complicates key distribution in microservice architectures. Never expose HMAC secrets in client-side code.

RSA and ECDSA algorithms (RS256, ES256) use asymmetric cryptography. The authorization server signs with a private key; resource servers verify with the public key. Public keys are often distributed via a JWKS (JSON Web Key Set) endpoint. This pattern scales better across multiple services.

The `alg` header field specifies which algorithm was used. A critical security vulnerability called algorithm confusion occurs when a server accepts tokens signed with `none` or when an attacker tricks the server into using a public key as an HMAC secret. Always explicitly whitelist allowed algorithms in your verification library.

Common Claims and Their Meaning

The `sub` (subject) claim identifies the user or entity the token represents — often a user ID. The `iss` (issuer) claim identifies who created the token, typically your authentication server URL. The `aud` (audience) claim lists intended recipients; verify that your service's identifier appears in this claim.

The `exp` (expiration) claim is a Unix timestamp after which the token must be rejected. Always check expiration server-side. The `iat` (issued at) claim records when the token was created. The `nbf` (not before) claim prevents use before a specified time — useful for scheduled token activation.

Custom claims like `role`, `permissions`, or `tenant_id` carry application logic. Keep custom claims minimal — large payloads increase header size on every request. Standard practice is to include only what is needed for authorization decisions and fetch additional user data from the database when necessary.

JWT Security Best Practices

Keep JWTs short-lived. Access tokens with 15-minute to 1-hour expiration limit the window of abuse if a token is stolen. Pair them with refresh tokens stored securely (httpOnly cookies) for seamless user experience without long-lived access tokens.

Transmit JWTs over HTTPS only. Tokens in URL query parameters leak through browser history, server logs, and Referer headers — use the `Authorization: Bearer <token>` header instead. Store tokens in memory or httpOnly cookies, never in localStorage if XSS is a concern.

Do not put sensitive data in the payload. JWTs are readable by anyone who intercepts them. Encrypt sensitive claims only if absolutely necessary (using JWE — JSON Web Encryption), but prefer keeping sensitive data server-side and referencing it by ID in the token.

JWT in Practice

OAuth 2.0 and OpenID Connect use JWTs for ID tokens and sometimes access tokens. When debugging OAuth flows, decode the ID token with the JWT Decoder to verify claims like `email`, `name`, and `sub` match expectations. Cross-reference with your identity provider's documentation for claim mappings.

Format decoded JWT payloads with the JSON Formatter for easier reading during team debugging sessions. If a token fails verification, check algorithm mismatch, clock skew (ensure server clocks are synchronized), and whether the signing key has been rotated.

For a broader understanding of how JWTs fit into API design, read our REST API Tutorial. For JSON fundamentals underlying every JWT payload, see What is JSON?.

Related Tools

Related Articles