🔐 JWT Decoder - JSON Web Token Parser

🔐
Structure:
Parts: (expected: 3)
Error:
⚡
🔧

        
📦

        
✍️
Base64URL:
Algorithm:
⚠️ Security Note: This tool does not verify signatures. Always validate JWT signatures on your server before trusting the data.
📊
Value:
Formatted:
🔍
(Base64URL)
⚠️

ℹ️ About JWT Decoder

JSON Web Tokens (JWT) are compact JSON claim sets used in access tokens, ID tokens, session systems, and API authorization headers. RFC 7519 defines JWT as a URL-safe representation of claims that is either signed as a JSON Web Signature (JWS, RFC 7515) or encrypted as a JSON Web Encryption (JWE). A signed JWT travels in compact form as header.payload.signature. Each segment is Base64URL encoded, the URL-safe alphabet from RFC 4648 section 5 that uses - and _ and omits = padding.

This decoder splits the token on its dots, decodes the header and payload JSON, shows the third segment as raw Base64URL text, and annotates every payload claim. Use it to inspect OAuth 2.0 or OpenID Connect bearer tokens, debug API authorization failures, check whether an exp timestamp has passed, compare the iss or aud claim with what you expect, or confirm which signing algorithm a service placed in the JOSE header. It reads tokens; it does not verify them.

The header carries JOSE metadata such as typ, alg and sometimes kid; the payload carries the registered claims listed under Output plus any application-specific claims such as scopes or roles; the signature is the value a relying party verifies with the expected algorithm, key, issuer and audience rules.

Supported inputs

  • One compact JWS token, pasted into the JWT Token box or sent as the API field token. Leading and trailing whitespace is trimmed. There are no other options: no key, algorithm or verification settings.
  • Exactly three dot-separated segments. Any other count, including the five segments of a JWE, is reported as a structure error together with the number of parts found.
  • Header and payload in unpadded Base64URL (A-Z, a-z, 0-9, -, _). Standard Base64 with + or /, = padding, a Bearer prefix, or whitespace inside a segment is rejected.
  • Each decoded segment must be a JSON object. Arrays, strings and other scalars are rejected. Payload bytes are decoded as UTF-8, so non-ASCII claim values display correctly.
  • The signature segment is taken verbatim and never decoded, so it may contain any characters and may even be empty (an unsecured alg: none token still has a valid structure).
  • Load Sample fills in a demo HS256 token whose exp is already in the past; Clear empties the input.

Output

The page re-parses on every keystroke and shows a Token Status panel (Structure Valid or Invalid, the number of parts found, and the exact error), the Header and Payload as pretty-printed JSON with Copy buttons, a Signature panel with the raw Base64URL segment and the alg value from the header (or Unknown), hidden when the signature segment is empty, a Claims Analysis card per payload claim, and the three Raw Token Parts with their own Copy buttons. Each claim card gives the meaning of the registered claims iss, sub, aud, exp, nbf, iat and jti (everything else is labelled Custom claim), the raw value, and for a numeric exp, nbf or iat a Formatted date-time in your local time zone, suffixed with (EXPIRED) when exp is earlier than now.

The API returns the same data as JSON: success, the echoed input, decodedJWT (header, payload, signature), tokenParts, tokenStatus (structure, parts, error), claimsAnalysis keyed by claim name (value, description, optional formatted) and a top-level error. A token that fails the structure or decoding checks returns HTTP 400 with tokenStatus.error explaining why.

Example

The example token from RFC 7519 section 3.1, eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk, decodes to the header {"typ":"JWT","alg":"HS256"}, the payload {"iss":"joe","exp":1300819380,"http://example.com/is_root":true} (the line breaks the RFC places inside the JSON vanish in the pretty-printed output) and the signature dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk. Token Status reports Structure Valid with 3 parts. Claims Analysis lists iss as Issuer, exp as Expiration Time with a formatted time of 2011-03-22 18:43:00 UTC rendered in your local zone and suffixed (EXPIRED), and http://example.com/is_root as Custom claim. The API panel below uses the widely circulated jwt.io demo token instead, whose payload is {"sub":"1234567890","name":"John Doe","iat":1516239022}.

Limitations

  • No signature verification, no issuer or audience validation, no revocation check, and no JWKS or key fetching. Everything shown in the payload is an unverified claim until a server validates the token.
  • Encrypted JWE tokens are not decrypted. Their five segments fail the three-part structure check, and the plaintext claims cannot be recovered without the decryption key.
  • Only exp is compared with the clock, using your device time at the moment of decoding and no leeway. nbf and iat are formatted but not checked, and timestamps stored as strings instead of numbers are shown raw.
  • The formatted date-time follows the locale and time zone of the machine doing the decoding: the browser on this page, the server when you call the API.
  • An alg of none, a missing typ, or an empty signature is not flagged; the tool reports what the header says without judging it.
  • Only unpadded Base64URL segments are accepted. The page does not strip = padding, a Bearer prefix, or percent-encoding from a token copied from a URL.

Browser or server processing

The interactive page runs the compiled logic module in your browser, so a pasted token never leaves your device. The public API (POST /api/tools/encoding-decoding/jwt) runs the same module on the server through the Node bridge and echoes the token back in input, so only the API path transmits the token. JWTs are bearer credentials that often carry personal data and privileges: use the page for live production tokens and send only test tokens through the API.

FAQ

Does decoding a JWT verify its signature?

No. Decoding only Base64URL-decodes the header and payload; the signature segment is displayed but never checked, so a tampered token decodes just as cleanly as a genuine one. Verification needs the issuer's key (the shared secret for HS256, or the public key for RS256, ES256 and EdDSA), an explicit allowlist of accepted alg values as RFC 8725 requires, and a recomputation of the signature over header.payload. The JWT Generator / Validator verifies HS256, HS384 and HS512 signatures when you supply the shared secret; it decodes but does not verify RS256, ES256 or EdDSA tokens.

Why does this JWT show as expired?

exp is a NumericDate, seconds since 1970-01-01T00:00:00Z. The tool compares it with your device clock at the moment of decoding and appends (EXPIRED) when it is in the past. If a token that should still be valid shows as expired, check that your machine's clock is correct and that the issuer wrote seconds rather than milliseconds; the built-in sample token is already expired (its exp is January 2018), so it always shows the flag.

Why does my token fail with "Invalid JWT structure" or "Failed to decode Base64URL"?

"Expected 3 parts" means the token does not contain exactly two dots: the value is a JWE with five parts, a dot was lost while copying, or it is not a JWT at all. "Invalid Base64URL characters" means a header or payload segment contains something outside A-Z a-z 0-9 - _, most often a Bearer prefix, = padding, a standard-Base64 + or /, or line breaks from a wrapped log line. "Invalid Base64URL length" means a header or payload segment was truncated to a length no Base64URL encoding can have (one stray character after the last complete 4-character block); a token cut off elsewhere inside the payload fails with a JSON parse error instead, and "Decoded JWT part is not a JSON object" means the segment decoded but does not hold a JSON object.

Is it safe to paste a real access token here?

On this page the token is decoded locally and is not sent anywhere, but it remains a live credential while it is on screen and in your clipboard. Treat it like a password: decode it on a trusted machine, clear the input when you are done, and do not share screenshots of the payload.

References

API Usage Example:

POST /api/tools/encoding-decoding/jwt
Content-Type: application/json

{
    "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"
}
Ready