Decode and inspect JSON Web Tokens. View the header algorithm, all payload claims, and expiry status. All decoding happens in your browser — no data is sent anywhere.
{
"alg": "HS256",
"typ": "JWT"
}{
"sub": "user_123456",
"iss": "https://auth.example.com",
"aud": "https://api.example.com",
"iat": 1719230000,
"exp": 1719233600,
"nbf": 1719230000,
"jti": "abcdef123456",
"permissions": [
"read:users",
"write:orders"
],
"role": "admin",
"email": "alice@example.com"
}This tool decodes JSON Web Tokens (JWT) defined in RFC 7519. Paste any JWT to instantly view the decoded header (algorithm and type), all payload claims with human-readable timestamps and expiry status, and the raw base64url-encoded signature. All decoding happens entirely in your browser — no token data is ever sent to a server.
A JWT consists of three dot-separated parts: HEADER.PAYLOAD.SIGNATURE. Each part is base64url-encoded (URL-safe base64 — uses - and _ instead of + and /). The header is a JSON object declaring the algorithm (alg: HS256, RS256, ES256, etc.) and token type (typ: JWT). The payload is a JSON object containing claims — registered claims like sub (subject), iss (issuer), exp (expiration), iat (issued at), nbf (not before), jti (JWT ID), and custom claims specific to your application. The signature is created by the issuer using the header + payload + a secret or private key — it proves the token was issued by a trusted party and has not been tampered with.
exp (Expiration Time): The token MUST NOT be accepted after this time. Value is Unix epoch seconds (integer). This tool highlights expired tokens in red. Short-lived access tokens (15 minutes to 1 hour) reduce the window of exposure if stolen. Long-lived tokens (days/weeks) should only be used for refresh tokens stored securely.
iat (Issued At): When the token was created. Useful for detecting tokens issued in the far past or future (clock skew attack).
nbf (Not Before): The token MUST NOT be accepted before this time. Used when a token is issued in advance for future use — for example, a scheduled access grant.
All three are in Unix epoch SECONDS (not milliseconds). A common bug is storing JWT exp as milliseconds (JavaScript Date.now() returns ms) — this creates tokens that expire 1000× sooner or appear far in the future.
HS256 (HMAC-SHA256): Uses a single shared secret for both signing and verification. Simple to implement but the secret must be shared between the token issuer and every service that verifies tokens. If any service is compromised, the secret is exposed and attackers can forge any token. Not suitable for distributed microservices. RS256 (RSA-SHA256): Asymmetric — the issuer signs with a private key, and any service verifies with the public key. The private key never leaves the auth server, making it safe to distribute the public key to all microservices. This is the recommended algorithm for production APIs. ES256 (ECDSA-SHA256): Asymmetric like RS256 but uses elliptic curve cryptography. Smaller key sizes (256-bit vs 2048-bit RSA) with equivalent security. Preferred in performance-sensitive environments. NEVER use alg: none in production — it disables signature verification entirely, allowing anyone to forge a valid token.
Token storage: Store JWTs in httpOnly cookies (not localStorage) for web applications — localStorage is accessible via JavaScript and vulnerable to XSS. httpOnly cookies are invisible to JavaScript and immune to XSS-based theft (though CSRF must be mitigated with SameSite=Strict or CSRF tokens). Token scope: Access tokens should carry the minimum required claims. Never put passwords, secrets, or sensitive PII in JWT payloads — they are base64-encoded, not encrypted, and readable by anyone. Use the aud (audience) claim to restrict which services can accept a token. Verification in code: always verify the signature and check exp before trusting any claim. JWT libraries like jsonwebtoken (Node.js), PyJWT (Python), and java-jwt do this automatically — never manually decode without verifying.
No — a standard JWT (JWS, JSON Web Signature) is signed but NOT encrypted. The header and payload are base64url-encoded, which is easily reversed by anyone who has the token. Never put sensitive data (passwords, social security numbers, credit card numbers, private keys) in a JWT payload. If you need encrypted tokens, use JWE (JSON Web Encryption), which is a different format defined in RFC 7516.
Because base64url decoding requires no key — the header and payload are just base64url-encoded JSON. The signature is the only part that requires a key to verify. This tool decodes (base64url reverse) but does not verify. Anyone who obtains a JWT can read its claims. This is why JWTs must be kept confidential (use HTTPS, store in httpOnly cookies) and must not contain sensitive data.
Use a JWT library, never implement verification manually. Node.js: jsonwebtoken — jwt.verify(token, secretOrPublicKey, {algorithms: ["RS256"]}). Python: PyJWT — jwt.decode(token, public_key, algorithms=["RS256"]). Java: java-jwt (Auth0) or jjwt. Always specify the allowed algorithms explicitly — some older libraries had the "none" algorithm vulnerability where setting alg to "none" in the header would bypass verification. Specify algorithms: ["RS256"] (or whatever you use) so the library rejects any other algorithm.
Access tokens are short-lived JWTs (typically 15 min to 1 hour) sent with every API request to prove identity. Short lifetimes minimize the damage if stolen. Refresh tokens are long-lived opaque tokens (days to weeks) stored securely (httpOnly cookie or secure storage) and used to obtain new access tokens when the current one expires — they are exchanged at the auth server, never sent to resource APIs. The user's session feels continuous (they don't need to log in again) but the access token exposure window is kept small.
The jti claim provides a unique identifier for each JWT instance. It's used to prevent replay attacks: if an attacker captures a valid JWT, they could resend it to the API (within its exp window). By maintaining a server-side blocklist of used jti values, the server can reject a token that has already been used — this is especially important for single-use tokens like password reset links. jti is typically a UUID or a random 128-bit value generated at token creation.