JWT Decoder
Decode and inspect JSON Web Tokens (RFC 7519) in your browser. Inspect Base64URL header parameters, payload claims, Unix expiration timestamps, and verify HMAC, RSA, or ECDSA signatures locally with zero server transmission.
HEADER (Algorithm & Token Type)
{
"alg": "HS256",
"typ": "JWT"
}PAYLOAD (Data & Claims)
Tue, 01 Jan 2030 00:00:00 GMT
Local: 1/1/2030, 12:00:00 AM
Wed, 01 Jan 2025 00:00:00 GMT
Local: 1/1/2025, 12:00:00 AM
VERIFY SIGNATURE (Local Web Crypto)
Alg: HS256Step-by-Step JWT Inspection Workflow
- Paste your encoded JWT string into the input area, or click one of the sample buttons (HS256 Active, Expired, or RS256 OIDC).
- Inspect the Header card to verify the cryptographic signing algorithm (alg), token type (typ), and key identifier (kid).
- Examine the Payload card to inspect standard identity claims (sub, iss, aud) and application-specific metadata.
- Check the Timestamp & Claims Inspector to review UTC and local date conversions for exp (Expiration), iat (Issued At), and nbf (Not Before) timestamps.
- Optionally provide your HMAC secret or RSA/ECDSA public key in PEM format to verify cryptographic integrity locally via the Web Cryptography API.
Compact JWT Serialization Anatomy (RFC 7519 & RFC 7515)
A compact JSON Web Token is serialized as three distinct Base64URL-encoded segments concatenated by period (.) delimiters:
Specifies token metadata: the cryptographic signing algorithm (alg, such as HS256 or RS256), token type (typ: "JWT"), and optional key identifier (kid).
Contains statements regarding the authenticated principal and contextual session metadata. Encodes registered timestamps (exp, iat, nbf), issuer (iss), audience (aud), and custom claims.
Calculated by executing the specified cryptographic hash or signing function over ProtectedHeader.Payload using the secret or private key. Enables recipient verification of data integrity.
Encoding Specification: Standard Base64 vs. Base64URL
RFC 7519 mandates Base64URL encoding (RFC 4648 §5) instead of standard Base64 (RFC 4648 §4) to ensure tokens remain safe for HTTP Authorization headers, query parameters, and web cookies without percent-encoding:
| Encoding Parameter | Standard Base64 (RFC 4648 §4) | Base64URL (RFC 4648 §5 / RFC 7519) | Engineering Rationale in JWTs |
|---|---|---|---|
| 62nd Character | + (plus) | - (minus / hyphen) | Eliminates conflicts in URLs where + represents encoded whitespace |
| 63rd Character | / (forward slash) | _ (underscore) | Prevents path segment collision and route misinterpretation in web servers |
| Padding Character | = (equals sign) | Omitted (No padding) | Prevents parameter key-value delimiter collisions; padding count is derived as (4 - (len % 4)) % 4 |
| Transport Safety | Requires URL percent-encoding | Safe in headers, URLs, and cookies | Guarantees zero mutation when passed in Authorization: Bearer <token> headers |
Standard Registered Claims Lifecycle & Gateway Validation (RFC 7519 §4.1)
RFC 7519 specifies seven standard registered claim names for interoperable token validation across identity providers and resource servers:
| Claim | Name | Type | Validation Condition | Gateway / Verifier Enforcement |
|---|---|---|---|---|
| exp | Expiration Time | NumericDate | currentTime < exp + leeway | Mandatory rejection with 401 Unauthorized if current Unix timestamp exceeds claim |
| nbf | Not Before | NumericDate | currentTime >= nbf - leeway | Rejects requests received prior to scheduled activation time; used for pre-issued batch tokens |
| iat | Issued At | NumericDate | iat <= currentTime + leeway | Enforces maximum token age and detects future-dated tokens caused by clock desynchronization |
| iss | Issuer | StringOrURI | iss === expectedIssuer | Strict string equality check against identity provider authority URL (e.g. https://auth.example.com) |
| aud | Audience | String | Array | aud.includes(targetAudience) | Rejects token if recipient API identifier is not listed; prevents cross-service privilege escalation |
| sub | Subject | String | sub !== empty | Unique principal identifier (user UUID, service account ID) within issuer domain scope |
| jti | JWT ID | String | !redisCache.has(jti) | Unique token nonce checked against distributed cache to implement single-use tokens and prevent replay attacks |
Production Clock Skew & Leeway Configuration
In distributed architectures, authorization servers and API gateways experience minor clock drift due to NTP sync intervals. Production verification engines (such as Envoy clock_skew_seconds or Node.js clockTolerance) recommend configuring a 30- to 60-second leeway. Without clock skew tolerance, a token issued milliseconds prior on an ahead-of-time server will be rejected immediately by a gateway whose clock is slightly behind.
Cryptographic Signing Algorithms Comparison (RFC 7518 JWA)
RFC 7518 specifies digital signature algorithms categorized into symmetric shared-secret schemes and asymmetric public-key cryptosystems:
| Algorithm | Cryptographic Family | Key Architecture | Signature Size | Verification Latency | Architectural Tradeoffs |
|---|---|---|---|---|---|
| HS256 | HMAC with SHA-256 | Symmetric shared secret (≥256 bits) | 32 bytes | ~10 µs | Fastest execution; requires distributing secret key to every verifier, creating multi-service key compromise risk |
| RS256 | RSASSA-PKCS1-v1_5 with SHA-256 | Asymmetric RSA (2048/4096-bit key pair) | 256 bytes | ~200 µs | Standard OIDC algorithm; public keys distributed safely via JWKS endpoints; higher CPU verification overhead |
| ES256 | ECDSA with NIST P-256 & SHA-256 | Asymmetric Elliptic Curve key pair | 64 bytes | ~60 µs | Compact signature size; equivalent cryptographic strength to 3072-bit RSA with 75% lower transmission payload overhead |
| EdDSA | Ed25519 Edwards-curve | Asymmetric Twisted Edwards curve | 64 bytes | ~25 µs | Constant-time execution immune to side-channel timing attacks; modern standard for high-throughput edge proxies |
Production Gateway Incident & Debugging Playbook
Diagnostic reference for troubleshooting common authentication failures encountered in edge proxies, API gateways, and microservices:
| Gateway Error | Root Cause Identification | Technical Verification Step | Engineering Remediation |
|---|---|---|---|
| 401 token_expired | Token exp claim timestamp is in the past, or gateway clock is running ahead of the auth server. | Compare token Unix exp against gateway system timestamp using date +%s. | Synchronize server clocks via NTP; implement client-side silent refresh rotation at exp - 30s. |
| 401 invalid_signature | Signing secret mismatch, PEM formatting error, or Base64 secret interpreted as plaintext string. | Verify whether authorization server imported secret as raw UTF-8 string or Base64-decoded byte array. | Ensure environment secrets match exact encoding; strip accidental trailing newline characters (\n) from config maps. |
| 403 audience_mismatch | Gateway resource identifier is missing from the aud string or array claim. | Inspect decoded payload aud claim; confirm it contains the target API resource URI. | Configure the OAuth 2.0 authorization server audience parameter during initial authorization code exchange. |
| 431 header_too_large | JWT exceeds proxy request header limits (typically 8 KB for Nginx / Envoy or 4 KB for cookies). | Check total token string byte size; identify oversized permission arrays or nested group structures. | Offload bulky group arrays from token payload to a backend userinfo endpoint or session store. |
Critical Security Vulnerabilities & Engineering Mitigations
The "alg: none" Exploit
Vulnerable libraries that dynamically trust the header alg parameter will skip signature verification if an attacker modifies the header to {"alg": "none"} and removes the trailing signature segment. Always hard-code allowed algorithms in verification options (e.g. algorithms: ['RS256']) and enforce rejection of unsigned tokens.
Key Confusion (CVE-2015-9235)
When a backend configured for RS256 processes a token where an attacker changed alg to HS256, a naive verifier may use the publicly available RSA public key as the HMAC symmetric secret. The verification passes because both parties possess the public key. Mitigate by verifying that the cryptographic key object type strictly matches the expected algorithm family before invoking verification routines.
Plaintext Exposure Risk (JWS vs. JWE)
A standard compact JWT is signed (JWS), not encrypted (JWE). The Base64URL encoding is trivial to reverse without cryptographic keys. Never store plaintext credentials, payment card data, personally identifiable information (PII), or internal database connection strings in unencrypted JWT payload claims.
Stateless Revocation Limitation
Because JWTs are stateless, an issued token cannot be revoked natively until its exp timestamp elapses. Production mitigation requires issuing short-lived access tokens (5–15 minutes) paired with stateful refresh tokens stored in HTTP-only cookies, or maintaining a distributed Redis blocklist for revoked jti claims.
Frequently Asked Questions
Can anyone decode and read a JWT without knowing the secret key?
Yes. A standard JSON Web Token (RFC 7519) is digitally signed (JWS), not encrypted (JWE). The Header and Payload are plain JSON strings serialized using Base64URL encoding. Anyone who intercepts or possesses the token can instantly decode and read all contained claims without a secret. Secrets or public/private key pairs are only required to create or cryptographically verify the signature, not to view the payload contents.
Is it safe to paste production JWTs into this online decoder?
Yes. This tool operates 100% client-side directly within your web browser. Token decoding, timestamp parsing, and cryptographic signature verification (via the native Web Cryptography API crypto.subtle) are executed locally in memory. No token strings, authorization headers, HMAC secrets, or PEM public keys are ever transmitted across the network, stored, or logged on any server.
What is the technical difference between decoding a JWT and verifying its signature?
Decoding is an unauthenticated deserialization process: it reverses the Base64URL encoding on the Header and Payload segments so you can inspect claims, algorithms, and timestamps. Verification is a cryptographic operation: it recomputes the digital signature over header.payload using an HMAC secret key or verifies an asymmetric signature against an RSA/ECDSA public key to prove mathematically that the token originated from a trusted issuer and was not altered in transit.
How do I check if a JWT has expired using its payload claims?
Inspect the standard "exp" (Expiration Time) registered claim in the payload. It contains a NumericDate Unix timestamp (seconds since January 1, 1970 UTC). If the current Unix timestamp (Math.floor(Date.now() / 1000)) exceeds the exp value, the token has expired. This tool automatically converts exp into UTC and local date formats and computes the remaining lifespan in real time.
Why does standard Base64 decoding fail or corrupt JWT strings?
JWTs mandate Base64URL encoding (RFC 4648 Section 5) rather than standard Base64 (RFC 4648 Section 4). Base64URL replaces "+" with "-" and "/" with "_", and strips all trailing "=" padding characters so tokens remain safe inside HTTP headers and query parameters without URL percent-encoding. Standard decoders like window.atob() fail unless "-" and "_" are substituted back and trailing "=" padding is restored mathematically via (4 - (len % 4)) % 4.
Why do I receive an "Invalid Token" or "Malformed JWT" error when pasting a token?
A valid compact JWT strictly requires three segments separated by periods (header.payload.signature). Common parsing failures include: (1) accidentally including the "Bearer " prefix from an HTTP Authorization header, (2) copy-pasting accidental whitespace or newlines, (3) submitting an encrypted JWE token (which consists of five dot-separated segments), or (4) corrupt Base64URL characters in the payload.
How can I verify an RS256 or ES256 token if my identity provider only provides a JWKS URL?
Identity providers (such as Auth0, Okta, Keycloak, or AWS Cognito) publish public keys as a JSON Web Key Set at /.well-known/jwks.json. To verify locally: (1) find the key object whose "kid" matches the "kid" in your token header, (2) extract the RSA modulus "n" and exponent "e" (or EC coordinates "x" and "y"), (3) convert them to PEM format (using tools like standard openssl or jwk-to-pem), and (4) paste the resulting PEM public key into the verification field of this tool.
