What Is a JSON Web Token (JWT)?
A JSON Web Token (JWT, pronounced "jot") is a compact, URL-safe way to represent claims between two parties. Defined in [RFC 7519](https://datatracker.ietf.org/doc/html/rfc7519), JWTs are the dominant token format for modern authentication and API authorization, you'll find them in OAuth 2.0 bearer tokens, OpenID Connect ID tokens, session cookies, and service-to-service API keys.
Unlike opaque session tokens (which are random strings your server looks up in a database), a JWT is self-describing: its payload carries the user's identity, permissions, and expiry directly inside the token. The server verifies the cryptographic signature rather than doing a database round-trip, which makes JWTs attractive for stateless, horizontally-scalable architectures.
The Three-Segment Structure
Every JWT is three Base64URL-encoded segments separated by dots:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
.eyJzdWIiOiJ1c2VyXzEyMyIsImV4cCI6MTcxNzAwMDAwMH0
.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
Header
The first segment is a JSON object describing the token's metadata:
{
"alg": "HS256",
"typ": "JWT"
}
alg tells the receiver which algorithm was used to sign the token. Common values: HS256 (HMAC-SHA-256, symmetric), RS256 (RSA-PKCS1v1.5, asymmetric), ES256 (ECDSA P-256, asymmetric), PS256 (RSA-PSS, asymmetric). The typ field is almost always "JWT".
Payload
The second segment contains the claims, statements about the subject and any additional application data:
{
"sub": "user_123",
"name": "Ada Lovelace",
"iss": "https://auth.example.com",
"aud": "my-app",
"iat": 1717000000,
"exp": 1717003600
}
Signature
The third segment is the cryptographic signature over base64url(header) + "." + base64url(payload). For HMAC algorithms the server holds the shared secret; for RSA/ECDSA algorithms the server holds the private key and clients verify with the public key. The signature is what prevents tampering, changing any byte in the header or payload invalidates it.
Important: Base64URL encoding is NOT encryption. Anyone who holds the token can decode the header and payload without any key. Never store sensitive data (passwords, credit card numbers, PII beyond a user ID) in JWT claims.
Standard Claims (RFC 7519)
| Claim | Full name | Meaning |
|---|---|---|
| `iss` | Issuer | Identifies who issued the token (e.g. `https://auth.example.com`) |
| `sub` | Subject | The principal the token refers to, typically a user ID |
| `aud` | Audience | Intended recipient(s), your API should reject tokens not addressed to it |
| `exp` | Expiration Time | Unix timestamp after which the token must be rejected |
| `nbf` | Not Before | Unix timestamp before which the token must be rejected |
| `iat` | Issued At | Unix timestamp when the token was created |
| `jti` | JWT ID | Unique identifier; useful for one-time tokens and revocation lists |
Application-specific claims (e.g. role, email, permissions) can be added freely alongside the standard ones.
Signing Algorithms: HS256, RS256, ES256
HS256 / HS384 / HS512 (HMAC-SHA)
Symmetric: the same secret is used to sign and to verify. Simple to implement, but every party that needs to verify tokens must hold the secret. Suitable for first-party APIs where the issuer and validator are the same service. Never expose the secret to clients.
RS256 / RS384 / RS512 (RSA)
Asymmetric: the issuer signs with a private key; verifiers use the corresponding public key. Public keys can be published safely via JWKS endpoints (/.well-known/jwks.json). Suitable when third parties need to verify tokens without trusting them with signing capability. Key size: at least 2048-bit RSA.
ES256 / ES384 / ES512 (ECDSA)
Asymmetric like RSA but with much shorter keys and signatures for the same security level. ES256 (P-256 curve) produces 64-byte signatures vs RS256's 256-byte signatures. Preferred for bandwidth-constrained environments (mobile, IoT). Requires careful implementation, a biased nonce is a critical vulnerability in ECDSA.
PS256 / PS384 / PS512 (RSA-PSS)
RSA with probabilistic padding (PSS), more secure than PKCS1v1.5 (RS256) and preferred by newer standards like FAPI. If you have a choice between RS256 and PS256 with the same key, use PS256.
Security Considerations
Never trust `alg: none`
The none algorithm means "no signature", some early JWT libraries would accept a token with "alg":"none" and no signature as valid, allowing trivially forged tokens. Your server must have an explicit allowlist of accepted algorithms and must reject none unconditionally.
Always validate `alg` server-side
Do not let the client's token header dictate which algorithm your server uses to verify. Pin the expected algorithm in your library configuration (e.g. jwt.verify(token, secret, { algorithms: ['HS256'] })). The "algorithm confusion" attack (switching RS256 to HS256 with the public key as the HMAC secret) is real and exploitable.
Validate `exp`, `nbf`, and `aud`
Expiry validation prevents replay attacks with stale tokens. Audience validation prevents a token issued for Service A from being accepted by Service B. Most libraries do these checks automatically, make sure you haven't disabled them.
Keep JWTs short-lived
The longer a token lives, the longer the window if it's stolen. Access tokens: 5–15 minutes. Refresh tokens: days to weeks, stored server-side with revocation support. If you need long-lived sessions, use refresh token rotation rather than a long-lived access token.
Do not store JWTs in localStorage for sensitive applications
localStorage is accessible to any JavaScript on the page, making it vulnerable to XSS. For high-security applications, store JWTs in HttpOnly; Secure; SameSite=Strict cookies, JavaScript cannot read them, so a successful XSS attack cannot exfiltrate the token directly.
Signature verification requires the key
The payload is public by design, this tool decodes it without any key. But to confirm a token was issued by a specific party and has not been tampered with, you must verify the signature using the issuer's secret (HMAC) or public key (RSA/ECDSA). Decode-only inspection is useful for debugging expiry, claim values, and algorithm, not for authorization decisions.
How This Tool Helps
Paste any JWT into the input and the decoder instantly:
- Splits the three segments and Base64URL-decodes header and payload
- Shows the raw JSON for both, formatted and indented
- Detects
expand displays a human-readable expiry status (VALID / EXPIRED / NOT YET VALID / NO EXPIRY) with the exact UTC timestamp and relative time ("2h ago", "5d from now") - Surfaces
iatandnbfwith the same human-readable treatment - Lists every claim with its RFC description for standard claims
- Identifies the signing algorithm and categorises it (symmetric / asymmetric)
- Shows the raw base64url signature segment for reference
Everything runs entirely in your browser, the token is never sent to any server. This makes the tool safe to use with production tokens during debugging.