Paste or upload a JWT to decode it and view the token content in a readable format in seconds.
header.payload.signature) and paste it into the input box. The decoder accepts JWS (signed) tokens only; encrypted JWE tokens require a private key and are not handled here.alg, typ, and optional fields like kid, jku, or x5c. The payload exposes every registered claim (iss, sub, aud, exp, nbf, iat, jti) and any custom claims your application added.exp and iat Unix timestamps with the Timestamp to Date Converter to confirm the token is still within its validity window. Compare aud against your API's expected audience and iss against the trusted issuer URL.Everything happens in your browser session via client-side JavaScript. The token is never transmitted to xconvert or any third-party server, so you can safely inspect access tokens that contain user identifiers, scopes, or tenant data.
JSON Web Tokens (RFC 7519) are the dominant token format for OAuth 2.0 access tokens, OpenID Connect ID tokens, API session credentials, and service-to-service authentication in microservice architectures. Because the header and payload are only Base64URL-encoded (not encrypted), anyone holding a JWS token can read its contents — that is by design, and it is exactly why a decoder is useful for debugging.
exp has passed, whether aud matches the resource server, and whether the granted scope covers the operation.sub, email, email_verified, and name. Decoding confirms the IdP sent what your app expects before you ship a relying-party integration.alg field for weak algorithms (HS256 with a guessable secret, or none), confirm exp - iat is reasonable (15 minutes for access tokens, hours for refresh tokens), and check that no PII is leaked in claims that downstream services log.kid rotation bugs — When key rotation breaks verification, the kid header value tells you which JWKS entry the token expects, so you can compare against the issuer's /.well-known/jwks.json.| Claim | Name | Type | Purpose |
|---|---|---|---|
iss |
Issuer | String / URI | Principal that issued the JWT; usually the IdP's HTTPS URL. |
sub |
Subject | String / URI | Principal the JWT is about; typically the user ID. |
aud |
Audience | String or string array | Recipients the JWT is intended for; receivers MUST reject if not present. |
exp |
Expiration Time | NumericDate (Unix seconds) | Token MUST NOT be accepted after this time. |
nbf |
Not Before | NumericDate (Unix seconds) | Token MUST NOT be accepted before this time. |
iat |
Issued At | NumericDate (Unix seconds) | Time at which the JWT was issued. |
jti |
JWT ID | String | Unique identifier; used to prevent replay and enable revocation lists. |
All seven are listed as optional but recommended in the spec. The aud, exp, and nbf validations are the ones servers most commonly get wrong — they are MUST-reject checks when the claims are present, not best-effort hints.
alg value |
Family | Key type | Notes |
|---|---|---|---|
HS256 |
HMAC + SHA-256 | Shared secret | Simplest; secret must be high-entropy (≥32 bytes) and never leaked. Default in many quickstart guides. |
HS384 / HS512 |
HMAC + SHA-384 / 512 | Shared secret | Stronger hash, otherwise identical to HS256. |
RS256 |
RSA-PKCS#1 v1.5 + SHA-256 | RSA key pair | Public key can be published via JWKS; private key signs. Most common for OIDC and large public issuers. |
RS384 / RS512 |
RSA + SHA-384 / 512 | RSA key pair | Stronger hash variants of RS256. |
PS256 / PS384 / PS512 |
RSA-PSS | RSA key pair | Modern PSS padding; preferred over RS* when supported. |
ES256 / ES384 / ES512 |
ECDSA + SHA-2 | EC key pair (P-256 / P-384 / P-521) | Smaller signatures and faster than RSA at equivalent strength. |
EdDSA |
Edwards-curve DSA | Ed25519 / Ed448 | Defined in RFC 8037; modern, deterministic, side-channel resistant. |
none |
(none) | — | Unsecured JWT. Tokens with alg=none MUST NOT be accepted by production verifiers. |
When verifying, always pin the expected algorithm on the server side. Do not derive the algorithm from the incoming token's alg header — that is the entry point for the algorithm-confusion class of attacks (Auth0 disclosure, March 31, 2015; CVE-2015-9235 covers the RS256→HS256 variant in node-jsonwebtoken < 4.2.2).
No. Decoding only Base64URL-decodes the first two segments and parses them as JSON. Anyone with the token can do this — that is why JWTs must be transmitted over TLS and treated as bearer credentials. Verification requires the signing key (HMAC secret for HS*, public key for RS* / ES* / EdDSA) and a vetted library (jsonwebtoken for Node.js, PyJWT for Python, jjwt for Java, golang-jwt/jwt for Go). The XConvert decoder is for inspection and debugging; it never asks for keys and never claims to validate authenticity.
A JWS-signed JWT is encoded, not encrypted. RFC 7515 specifies Base64URL encoding for the header and payload, which is a reversible transform that exists to make the token URL- and HTTP-safe — it is not a cipher. The signature segment is the only part that depends on the key, and even that is a MAC or signature over the encoded bytes, not an encryption of them. If you need confidentiality, use JWE (see below) or move the sensitive data out of the token entirely.
JWS (RFC 7515) signed tokens are not — they provide integrity and authentication only, and the payload is readable by anyone holding the token. JWE (RFC 7516) tokens are encrypted with authenticated encryption (typically A256GCM or A128CBC-HS256) and require a decryption key to read. JWEs have five Base64URL segments separated by dots rather than three. If a token has five segments, this decoder will not handle it — use a server-side JWE library with the appropriate private key.
alg=none?Critical. Auth0's original March 2015 disclosure documented multiple popular libraries that accepted tokens with "alg":"none" and an empty signature as valid, letting attackers forge arbitrary claims and impersonate any user. Modern libraries reject none by default, but the failure mode reappears whenever a verifier reads the algorithm from the incoming token instead of pinning it server-side. Defense: pass an explicit allowlist ({algorithms: ['RS256']} in jsonwebtoken, algorithms=["RS256"] in PyJWT) and never use the no-arg verify() form.
exp and nbf correctly?Both claims are NumericDate values — seconds (not milliseconds) since 1970-01-01T00:00:00Z UTC. Reject when now < nbf or now >= exp. RFC 7519 permits a small leeway (typically 30-60 seconds) to absorb clock skew between issuer and verifier; most libraries expose this as a clockTolerance or leeway option. Do not skip the check just because the token "looks fresh" — an absent exp paired with a missing leeway check is a long-lived token in disguise.
kid header for?kid (key ID) is an optional header parameter (RFC 7515 Section 4.1.4) that names which key in the issuer's key set was used to sign the token. Issuers publish their public keys at /.well-known/jwks.json — each entry has a matching kid. During key rotation, the issuer signs new tokens with the new kid while keeping the old key in the JWKS until existing tokens expire. Verifiers should look up the key by kid from a cached JWKS, not trust any URL the token itself points to (jku and x5u headers are spec-defined but operationally risky — pin the JWKS URL out of band).
PASETO (Platform-Agnostic Security Tokens) was designed in 2018 specifically to remove JWT's footguns. Its versioned protocols (v4.public, v4.local) hard-code a single modern algorithm — Ed25519 for signed public tokens, XChaCha20-Poly1305 for symmetric local tokens — so there is no alg header to confuse, no none algorithm, and no negotiation. Trade-offs: PASETO has narrower ecosystem support, no JWKS equivalent, and is not understood by external IdPs like Auth0 or Okta. Pragmatic split many teams adopt: keep JWT for federated OIDC where compatibility is mandatory, use PASETO (or signed cookies) for first-party service-to-service tokens you control end-to-end.
exp and iat?Both are NumericDate values measured in Unix seconds (RFC 7519 Section 2). For example, 1735689600 is 2025-01-01T00:00:00Z. Pipe the value through the Timestamp to Date Converter for a readable date, or in code use new Date(exp * 1000) (JavaScript) or datetime.fromtimestamp(exp, tz=timezone.utc) (Python). The seconds-not-milliseconds distinction trips up developers porting from JavaScript's Date.now() constantly — multiplying by 1000 too many or too few times is the most common timestamp bug in JWT code.
The XConvert JWT Decoder is read-only. Changing any byte of the header or payload invalidates the signature, so the verifier will reject the modified token unless you re-sign it with the issuer's key (which you should not have). If you need test fixtures with custom claims, use a JWT library that issues new tokens, or generate them with a tool that controls the signing key — never try to "edit" a production token.
Related tools: Base64 Decoder · JSON Formatter · Unix Timestamp to Date · URL Decoder · HTML Entity Decoder