Inspect & Identify

JWT Inspector

Paste a JWT to see its header, claims and expiry, flag risky algorithms, and verify the signature with a public key. Everything runs in your browser.

Signature verification

Paste the issuer’s JWKS JSON, not its URL: this page makes no network requests. Private keys are refused.

Verify an HS256/HS384/HS512 token with a shared secret (this page only)

Checked with Web Crypto in this tab. The secret is never sent anywhere, and the API has no equivalent: the service never accepts secrets.

Keyboard shortcuts

Esc
Close a menu or overlay, then leave full screen
↓ on a menu
Open it; ↑ ↓ move through its items
← → in the menu bar
Move between menus

Where your data goes

Using this page Using the API, MCP or A2A
Where it runs In your browser. The token is decoded, and its signature checked with jose and Web Crypto, in this page; the public key and any HMAC secret you type stay in the tab, and the page makes no network requests (it never fetches JWKS, jku or x5u URLs). In a Cloudflare Pages Function at the Cloudflare data centre nearest the caller.
What leaves your device Nothing you enter. After the page and its scripts load, no request carries your input. The browser enforces this: the page's Content-Security-Policy sets connect-src 'none' and form-action 'none', which block fetch, XHR, WebSocket, EventSource, beacons and form posts.

The server receives the token and, if given, a public key. It decodes and verifies them in memory and returns the result; the input is not stored or logged (only the per-call metadata row is recorded). The server makes no network requests (it never fetches jku, x5u or JWKS URLs). Tokens are bearer credentials: a token that has not expired grants access to whoever holds it, so prefer the page (which decodes in your browser) for live production tokens, or send tokens that are expired or from test systems.

Stored Nothing leaves the page. No cookies, analytics or third-party scripts; the browser keeps only your View → Inline config choice. Your inputs and results: never. What is stored is your client record (client ID, a SHA-256 hash of your secret, expiry, and the profile you registered with) and one metadata row per call: operation, time, transport, status, error code, duration, request and response sizes, and country.
Logged Nothing (no requests are made). Only the per-call metadata above, attributed to your client ID. Never parameters, bodies, results, or credentials. Cloudflare, as the host, also processes request metadata (IP address, full URL including the query string, headers) under its own policies, so put inputs in POST bodies.
Access Open to anyone. Requires a client ID and secret (how to get one). HTTPS only; TLS terminates at Cloudflare.

Details and how to verify this yourself: Security & privacy.

User guide

The tool sits in a window that works like a desktop app: menus on the top row and the full-screen icon at its right (Esc leaves full screen). The set-up options described below are in Settings → Options…, an overlay, and the Settings menu also lists the common choices directly. To keep the options in view instead, choose View → Inline config; the page remembers that choice. Help → Keyboard shortcuts… lists the keys.

  1. Paste the token. A leading Bearer , surrounding quotes and line breaks are removed for you, with a note.
  2. Read the summary card: the algorithm, issuer, subject, audience, and the three time claims with how long ago or how far ahead they are. Red pills flag an expired token, one not yet valid, alg: none, an unusual algorithm, or a missing exp.
  3. To verify the signature, paste the issuer’s public key: its JWKS JSON (from the jwks_uri in its OpenID configuration), a single JWK, a PUBLIC KEY PEM, or the signing certificate. The banner turns green only when the signature verifies.

HMAC tokens (HS256, HS384, HS512) are signed with a shared secret, not a key pair. Open Verify … with a shared secret and type the secret: it is checked in this tab with Web Crypto and never sent anywhere. The API cannot do this (see below).

Decoding is not verifying. Anyone can create a token with any claims. Until the banner says Signature valid with the issuer’s key, treat every claim as untrusted input.

Tokens are credentials. A token that has not expired lets whoever holds it act as its subject. This page decodes it locally; be careful where else you paste it.

Specification

Formats.

  • JWS compact serialization (RFC 7515 §7.1): three base64url segments, header.payload.signature. The header must be a JSON object. If the payload is a JSON object it is the JWT claims set (RFC 7519); otherwise it is shown as text (payloadText).
  • JWE compact serialization (RFC 7516 §7.1): five segments. Only the protected header is decoded. The content cannot be read without the recipient’s key, which the API never accepts.
  • Encoding: segments must be unpadded base64url (RFC 7515 §2). A token containing +, / or = is rejected with an explanation, because conforming verifiers reject it too.
  • Not supported: JWS/JWE JSON serialization. "b64": false (RFC 7797) payloads are shown as text.
  • Duplicate JSON members: the last one wins (JSON.parse behaviour).

Registered claims (RFC 7519 §4.1).

ClaimOutput
iss, sub, jtiString, or null with a warning if it has another type
audAlways an array: a single string becomes a one-item array
exp, nbf, iatvalue (seconds, as given), iso (UTC), and secondsFromAt = value − reference time; negative is in the past

A NumericDate that is not a JSON number is ignored with a warning. A value above 10¹¹ triggers a warning that it is probably in milliseconds.

Status flags, evaluated at the reference time at (default: now) with clock_tolerance seconds of leeway (default 0):

FlagRule
expiredat ≥ exp + tolerance. The token is invalid at the exp instant (RFC 7519 §4.1.4)
notYetValidat < nbf − tolerance
issuedInFutureat < iat − tolerance
missingExpThe payload is a claims set without exp
algNonealg is none (RFC 7518 §3.6): unsecured, anyone can forge it
weakAlgorithmalg is none, or names SHA-1 or MD5 (for example RS1, HS1)
unusualAlgorithmalg is not registered (including the wrong case, such as hs256), or is ES256K, Ed448 or ML-DSA
symmetricHS256/HS384/HS512

Other checks reported as warnings.

  • Signature length: HS*, ES*, Ed25519 and Ed448 signatures have a fixed size. A wrong length is flagged; for ECDSA this usually means the signature was DER-encoded instead of raw r‖s (RFC 7518 §3.4).
  • Key-location headers: jku and x5u are never fetched, and an embedded jwk or x5c is never used to verify. Trusting a key that the token itself supplies is a known attack.
  • crit extensions are listed. Unknown critical extensions make verification fail, as RFC 7515 §4.1.11 requires.

Signature verification.

  • Key formats: a JWK, a JWKS ({"keys": [...]}, or a bare array), a PUBLIC KEY (SPKI) PEM, or a CERTIFICATE PEM. Certificate validity, chain and revocation are not checked; only its public key is used.
  • JWKS key selection: when the token has a kid, only keys with that kid are considered. Then a key must have the right kty and curve for the algorithm, alg absent or equal to the token’s, and use not enc. Every remaining key is tried, and the first that verifies wins.
  • Algorithm: the token’s own alg is the only one allowed. jose rejects RSA keys smaller than 2048 bits.
  • Supported algorithms: RS256/384/512, PS256/384/512, ES256/384/512, EdDSA (Ed25519 keys) and Ed25519. ML-DSA-44/65/87 work only where the runtime’s Web Crypto supports them. ES256K and Ed448 are reported as unverifiable.
  • Outcomes: valid; invalid-signature (the key does not match: the token was altered, or a different key signed it); or unverifiable, with an error explaining why (no key with that kid, wrong key type, alg: none, HMAC, unsupported algorithm).

Why HMAC tokens cannot be verified through the API. HS256/384/512 use one shared secret both to sign and to verify, so anyone who can verify can also forge tokens. This service never accepts secrets:

  • key values with kty: "oct" or a k member are refused.
  • So are private JWKs (d, p, q, dp, dq, qi, oth, priv) and PEM blocks labelled PRIVATE KEY.

If a token says HS256 but the issuer normally signs with RS256 or ES256, it may be an algorithm-confusion attack: the attacker signs with the public key used as an HMAC secret. Reject it.

No network access. The API and the page never fetch anything, so key cannot be a URL. To verify against an issuer’s keys:

  1. Fetch https://<issuer>/.well-known/openid-configuration yourself.
  2. Take its jwks_uri and fetch that.
  3. Pass the JSON you got as key.

Limits. API token and key: at most 65,536 characters each.

API & MCP

The same logic is available over HTTP and as MCP tools. Unlike this page, these run on the server: see where your data goes.