JWT Decoder / Encoder

Decode any JSON Web Token to inspect its header and payload claims, or build and HMAC-sign a new token with HS256, HS384, or HS512 — no library, no server, runs entirely in your browser.

🔍 Decode
Paste JWT Token
Paste a JWT token above to visualize and decode it
✍️ Encode & Sign
Algorithm
Secret
Header JSON
Payload JSON
Signed JWT
Fill in the payload above, then click Sign Token.

What Is a JSON Web Token (JWT)?

A JSON Web Token (JWT, pronounced "jot") is a compact, URL-safe token format defined in RFC 7519 for securely transmitting information between parties as a signed JSON object. JWTs are the backbone of modern stateless authentication — used in REST APIs, single-page applications, mobile backends, and microservice architectures worldwide.

Every JWT is made of three Base64URL-encoded parts separated by dots: the Header (algorithm and token type), the Payload (claims about the subject), and the Signature (HMAC or RSA hash that proves the token was not tampered with). The header and payload are merely encoded — not encrypted — so anyone who intercepts the token can read their contents. Only the signature requires the secret key to verify.

How JWT Authentication Works — Step by Step

The standard JWT authentication flow follows these steps:

  1. Login — The client sends credentials (username/password, OAuth code, etc.) to the authentication server.
  2. Token issued — The server validates credentials, creates a payload with claims (sub, exp, roles…), signs the token with its secret key, and returns the JWT to the client.
  3. Token stored — The client stores the JWT (in memory, an HttpOnly cookie, or localStorage).
  4. Authenticated requests — On every API call, the client attaches the JWT: Authorization: Bearer <token>.
  5. Verification — The API server verifies the signature with its secret key, checks exp, iss, and aud, then reads the payload to authorize the request — with no database lookup required.

Standard JWT Claims Explained

The JWT spec defines seven registered claim names, each with a precise meaning:

  • sub (Subject) — Who the token refers to, typically a user ID like "user_abc123".
  • iss (Issuer) — The entity that issued the token, e.g. "https://auth.myapp.com".
  • aud (Audience) — Who the token is intended for. Servers should reject tokens not addressed to them.
  • exp (Expiration) — Unix timestamp after which the token must be rejected. Always set this.
  • iat (Issued At) — Unix timestamp when the token was created. Useful for age checks.
  • nbf (Not Before) — Unix timestamp before which the token must not be accepted.
  • jti (JWT ID) — A unique identifier; used to build a token blocklist for revocation.

HS256 vs HS384 vs HS512 — Choosing an Algorithm

All three HMAC variants use a shared secret key — the same key both signs and verifies the token. The only difference is the underlying SHA-2 hash size:

  • HS256 (HMAC-SHA256) — The default. A 256-bit signature, widely supported, suitable for the vast majority of applications. Use this unless you have a specific reason not to.
  • HS384 (HMAC-SHA384) — Marginal security improvement. Rarely justified in practice.
  • HS512 (HMAC-SHA512) — Maximum HMAC strength. Useful for high-security environments or regulatory requirements.

For scenarios where the signing and verification parties are different (e.g., a third-party API consuming your tokens), use asymmetric algorithms: RS256 (RSA) or ES256 (ECDSA). These require a key pair and are not handled by this tool, which only supports HMAC signing.

JWT Security Best Practices

  • Always verify the signature server-side before trusting any claim in the payload.
  • Set short expiry times — 15 minutes to 1 hour for access tokens. Use refresh token rotation for longer sessions.
  • Use a strong, random secret — at least 256 random bits for HS256. A weak secret can be brute-forced.
  • Never store sensitive data in the payload — the payload is Base64-encoded, not encrypted. Anyone who intercepts the token can read it.
  • Validate all registered claims — check exp, iss, aud, and nbf on every request, not just the signature.
  • Reject alg: none — never accept unsigned tokens on a server that expects signed ones.
  • Always use HTTPS — treat JWTs like passwords; never transmit them over plain HTTP.

Examples

JWT structure at a glance

Three dot-separated Base64URL strings:

eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ1c2VyMTIzIn0.Xk5C8HLqrHXSf...

Red = Header · Purple = Payload · Cyan = Signature

Sending a JWT with curl

curl -H "Authorization: Bearer eyJhbGci..." \
  https://api.example.com/profile

Typical access token payload

{
  "sub": "user_abc123",
  "iss": "https://auth.myapp.com",
  "aud": "https://api.myapp.com",
  "exp": 1735693200,
  "iat": 1735689600,
  "roles": ["user","admin"]
}

Verifying a JWT in Node.js

import jwt from 'jsonwebtoken';
const payload = jwt.verify(
  token,
  process.env.JWT_SECRET,
  { algorithms: ['HS256'] }
);

JWT is decoded, not verified — and the difference is how authentication breaks

A JWT (JSON Web Token) is three Base64url-encoded JSON objects separated by dots: header.payload.signature. The decoder on this page shows you what is in a token. It does not tell you whether the token is trustworthy. Those are different operations, and confusing them is how authentication systems have been broken in production for the last decade.

Decoding is free; verification requires a key

Anyone can decode any JWT — including this tool, the attacker, and the user’s browser DevTools. Base64url is not encryption. The payload of every JWT you have ever issued is readable to whoever holds the token. Verification, on the other hand, requires the signing key and recomputing the signature over header.payload. Only the server that issued the token (or holds the public key, for asymmetric algorithms) can do that.

Algorithms: HS256, RS256, ES256, and the “none” trap

HS256: HMAC with SHA-256, symmetric (same key signs and verifies). Fast, simple, but the signing key must be held only by the issuer — if a client needs to verify, you need RS256. RS256: RSA, asymmetric. Public key can verify, only private key can sign. ES256: ECDSA with P-256, asymmetric, smaller signatures than RS256. none: the historic disaster — if your library trusts the alg field from the token and the attacker sets it to none, the signature check is skipped. CVE-2015-9235 hit multiple major libraries with this. Lesson: enforce the algorithm on the server side, never let the token decide.

Time claims: exp, nbf, iat

exp (expiration) is a Unix timestamp; tokens after that time must be rejected. nbf (not before) is the earliest valid time. iat (issued at) is informational. Allow a small clock-skew tolerance when validating — the convention is 30 seconds — because client clocks drift. Reject anything older than your refresh-token lifetime regardless of what the token says.

Audience and issuer: aud, iss, sub

iss identifies the issuer; verify it matches the server you trust. aud identifies the intended audience; if you have multiple APIs sharing a signing key, aud prevents a token issued for service A from authenticating to service B (confused-deputy attack). sub identifies the user. Validate all three on every request, not just on first login.

Storage: cookie vs localStorage, and the XSS/CSRF trade-off

Cookies with HttpOnly; Secure; SameSite=Lax are safe from XSS exfiltration but vulnerable to CSRF unless you add anti-CSRF tokens. localStorage is immune to CSRF (the browser does not send it automatically) but readable from any XSS payload on your domain. You cannot have both. Choose based on whether XSS or CSRF is your bigger risk in context — for SPAs with strong CSP and no script injection points, localStorage is defensible; for traditional apps with many forms, cookies + CSRF tokens is the conservative choice.

Why JWTs are bad at revocation

A signed JWT is valid until it expires. Revoking a session before that means either keeping a server-side deny-list (which defeats the “stateless” pitch of JWTs) or accepting that compromised tokens are valid until exp. The practical pattern: short access tokens (5–15 min), longer refresh tokens (days), refresh tokens stored in a database that can be invalidated. The JWT is fast to verify; the refresh is the real session.

Takeaway: The decoder on this page is for debugging — inspecting headers, reading claims, troubleshooting why a request was rejected. It is not, and cannot be, a substitute for server-side verification. To verify a token in real code: (1) hold the signing key server-side, (2) enforce the expected algorithm (reject none and unexpected algorithms), (3) validate exp, nbf, iss, aud, (4) keep a refresh-token deny-list for revocation. Client-side JWT verification is theatre — the client controls the verifier.

Sources: RFC 7519 (JWT) · RFC 7515 (JWS) · OWASP JWT cheatsheet.

Frequently Asked Questions