🔑 JWT Debugger — Decode & Verify
| Claim | Value | Meaning |
|---|
💡 Decode needs no key. For signature verification: HS256/HS384/HS512 → paste the shared secret; RS256/RS384/RS512 → paste the RSA public key (PEM); ES256/ES384/ES512 → paste the EC public key (PEM). Asymmetric verification never requires the private key. Everything runs locally with the Web Crypto API — nothing is uploaded.
📖 What is a JWT (JSON Web Token)?
A JSON Web Token (JWT) is a compact, URL-safe token format defined by RFC 7519 used to transmit claims securely between two parties — typically between an authentication server and your application, or between a frontend and a backend API.
Unlike opaque session IDs that require a server-side lookup, a JWT is self-contained: all the information the server needs (who the user is, when the token expires, what the user is allowed to do) is embedded directly in the token itself. That makes JWTs the standard choice for stateless authentication in REST APIs, single-page applications, mobile apps, and microservices — you will meet them in OAuth 2.0, OpenID Connect, Firebase Auth, Auth0, AWS Cognito, and countless enterprise SSO setups.
A typical token looks like this:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
When you paste this token into the debugger above, you will see it split into its three parts instantly. The debugger is the fastest way to understand what any JWT actually contains — whether it is a token from your own login flow, a third-party API, or a sample in documentation.
🧩 The Three-Part Structure — Header, Payload, Signature
Every JWT is a dot-separated string with exactly three segments: header.payload.signature. Each segment is base64url-encoded (the URL-safe variant of base64, where + becomes - and / becomes _, and padding = is stripped).
1. Header
The header is a small JSON object that describes how the token was signed. It almost always contains:
alg— the signing algorithm, e.g.HS256,RS256, orES256. This is the only required field.typ— the token type, normally"JWT".kid— (optional) the key ID, used when the verifier has multiple keys and must pick the right one. Common with JWKS endpoints.cty— (optional) content type, only present for nested tokens.
Example: {"alg":"HS256","typ":"JWT"}
2. Payload
The payload contains the claims — statements about the subject and metadata about the token. Claims come in three flavors:
- Registered claims — standardized, optional-but-recommended names defined by the JWT spec (
iss,sub,aud,exp,nbf,iat,jti). - Public claims — custom claims registered in the IANA registry or defined by your application (e.g.
scope,roles). - Private claims — custom claims agreed between your own parties (e.g.
"user_id": 42).
Example: {"sub":"1234567890","name":"John Doe","iat":1516239022,"admin":true}
3. Signature
The signature is computed over the string base64url(header) + "." + base64url(payload) using the algorithm in the header and a key that only the token issuer knows (for HMAC) or the issuer's private key (for RSA/ECDSA). It is the security backbone of the JWT: if anyone edits the payload, the signature no longer matches and the token is rejected by any honest verifier.
Note that JWT is signed, not encrypted. The header and payload are only base64-encoded — anyone can read them without any key. Never put passwords, credit-card numbers, or other secrets inside a JWT payload. If you need confidentiality, use JWE (JSON Web Encryption) instead.
📋 Registered Claims Explained
The JWT spec reserves seven claim names. The debugger above highlights them in a table automatically whenever they are present, converting Unix timestamps into human-readable dates:
| Claim | Full Name | What It Means |
|---|---|---|
iss | Issuer | Who created and signed the token (a URL or identifier, e.g. https://auth.example.com). Verifiers should check this matches their trusted issuer. |
sub | Subject | The principal the token is about — usually the user ID. Must be unique per issuer and never reused. |
aud | Audience | Who the token is intended for (an API, a client ID, or an array of them). Recipients must verify they are in the audience. |
exp | Expiration Time | Unix timestamp (seconds) after which the token is invalid. The most common claim to debug — see the expiry badge in the tool. |
nbf | Not Before | Unix timestamp before which the token must NOT be accepted. Useful for tokens that only become valid at a scheduled time. |
iat | Issued At | Unix timestamp of when the token was issued. Lets servers estimate token age and rotate long-lived sessions. |
jti | JWT ID | A unique identifier per token, used to prevent replay attacks (the server remembers used jti values). |
Unit gotcha: all JWT time claims are in seconds. JavaScript's Date.now() returns milliseconds — a classic bug is issuing a token with exp: Date.now() instead of Math.floor(Date.now()/1000), which makes the token look expired by decades. When debugging an "immediately expired" token, check the raw number first.
🔐 Signing Algorithms: HS256 vs RS256 vs ES256
The alg header decides both the cryptographic algorithm and which key model is used. There are two families:
HMAC — HS256 / HS384 / HS512 (symmetric)
- One shared secret is used for both signing and verifying.
- HS256 = HMAC-SHA256, HS384 = HMAC-SHA384, HS512 = HMAC-SHA512.
- Fast and simple — ideal for a single trusted server signing its own tokens (e.g. one backend authenticating its own API).
- Danger: anyone who knows the secret can forge valid tokens. Never embed the secret in client-side code, and never share it across untrusted parties.
- To verify in this debugger: paste the token and type the shared secret into the key field.
RSA — RS256 / RS384 / RS512 (asymmetric)
- Issuer signs with the private key; anyone verifies with the matching public key.
- This is what OAuth 2.0 / OpenID Connect providers (Auth0, Okta, Google, Azure AD) use. They publish their public keys on a JWKS endpoint (
/.well-known/jwks.json) so any client can fetch the current key bykidand verify tokens without talking to the issuer. - Verification here only needs the PEM public key — paste it into the key field.
ECDSA — ES256 / ES384 / ES512 (asymmetric, elliptic curve)
- Same public/private model as RSA but with much smaller keys and faster math (P-256 curve for ES256).
- Increasingly popular in modern systems (e.g. Apple, some Firebase configurations).
- Also verifiable with just the EC public key in PEM format.
⚙️ How JWT Signature Verification Works
Verifying a JWT is a four-step process, and you can watch every step happen in the debugger above:
- Split the token into its three segments at the dots. A token with fewer or more than two dots is malformed.
- Read the
algclaim from the decoded header. This tells you which key and algorithm to use. Reject tokens whosealgyou did not expect (see thealg:noneattack below). - Recompute the signature locally over the exact byte string
segment1 + "." + segment2— with the shared secret (HMAC) or by verifying against the public key (RSA/ECDSA). This tool uses the browser's native Web Crypto API (crypto.subtle), the same primitives Node.js and browsers use. - Compare the computed signature with segment 3. If they match, the token is authentic and unmodified; if not, the token was tampered with, signed with a different key, or corrupted in transit.
Signature validity is only half the story — a production verifier must also check the claims: exp not passed, nbf reached, iss matches your issuer, and aud includes your application. A token with a perfect signature can still be expired or targeted at a different service.
🔍 Common JWT Debugging Scenarios & Errors
1. "Token expired" immediately after login
Almost always a seconds-vs-milliseconds bug (Date.now() instead of Date.now()/1000) or a timezone/clock-skew issue on the server. Decode the token and look at the raw iat / exp values — if they are 13-digit numbers, they are milliseconds.
2. Signature verification fails with a valid-looking token
- Wrong key: the secret or public key does not match the one used at signing time. If the header has a
kid, confirm you are using the key with that ID. - Trailing whitespace: a copied secret or key with an invisible newline breaks the signature. Paste into the debugger and check for stray characters.
- Algorithm mismatch: a token signed with RS256 cannot be verified with an HS256 secret — the header
algmust match the key type. This mismatch is also the basis of a famous attack (see below), so verifiers must pick the algorithm from an allow-list, never from the token alone. - Key format: PEM keys must include the full
-----BEGIN PUBLIC KEY-----…-----END PUBLIC KEY-----block.
3. Payload decodes but shows gibberish
The payload segment is not valid JSON. Some tokens embed non-JSON payloads (rare, but permitted by the spec). If the base64url decodes to readable text that is not JSON, the token may use a custom serialization — most commonly you will still see valid JSON, so gibberish usually means a copy/paste error truncated the token.
4. "Invalid JWT format" — wrong number of parts
You pasted a token that is not a JWT (e.g. an OAuth opaque access token, a session cookie, or a SAML assertion), or the token got truncated. JWTs always have exactly two dots. Some systems prepend Bearer — strip that prefix first.
🛡️ JWT Security Pitfalls to Avoid
- Never trust the
algheader blindly. The classic alg:none attack tricks naive verifiers into accepting a token with"alg":"none"and an empty signature — an attacker simply removes the signature and changes the payload to"admin":true. Verifiers must rejectnoneoutright unless explicitly intended, and should validatealgagainst a server-side allow-list. - Watch the RS256→HS256 confusion attack. If a verifier expects RS256 but accepts HS256, an attacker can take the issuer's public key, use it as the "HMAC secret", and forge a token the verifier accepts. The fix is an explicit algorithm allow-list, never deriving the algorithm from the token.
- Verify the claims, not just the signature. Always check
exp,nbf,iss, andaud. A stolen but unexpired token is still dangerous — keep access-token lifetimes short and use refresh tokens or re-authentication for longer sessions. - Keep secrets out of client code and out of the payload. JWT payloads are readable by anyone; storing a password or API key inside one is equivalent to publishing it. And an HMAC secret shipped in a browser bundle lets every visitor forge tokens.
- Use HTTPS everywhere. A JWT captured over plain HTTP can be replayed. Always transmit tokens over TLS.
- Do not store JWTs in localStorage if XSS is a concern. A single injected script can read them. HttpOnly cookies (or short-lived in-memory tokens) are a safer default for SPAs.
❓ Frequently Asked Questions
What is a JWT debugger?
A JWT debugger is a tool that decodes a JSON Web Token into its three readable parts — header, payload, and signature — and lets you inspect registered claims such as issuer, subject, audience, and expiration. Advanced debuggers (like this one) also verify the token signature so you can confirm a token is authentic and has not been tampered with.
Can I verify a JWT signature in the browser?
Yes. Paste the JWT plus your shared secret (for HS256/HS384/HS512) or your RSA/EC public key (for RS256/RS384/RS512/ES256) and the tool computes the signature locally using the Web Crypto API. You get a clear VALID or INVALID result without any data leaving your browser.
Is this JWT debugger really free and private?
Yes. There is no sign-up, no usage limit, and no server involved at all. Decoding and signature verification run 100% client-side with the Web Crypto API, so your token, secret, and keys never leave your device.
What does the three-part JWT structure mean?
A JWT looks like xxxxx.yyyyy.zzzzz. The first part is the base64url-encoded header (algorithm and token type), the second is the base64url-encoded payload (the claims), and the third is the signature computed over header.payload using the algorithm named in the header. The signature is what prevents someone from editing the payload without invalidating the token.
Why does my JWT show an EXPIRED badge even though it was just issued?
The exp claim is a Unix timestamp in seconds, not milliseconds. If a token was created with exp in milliseconds (a common mistake), it appears expired decades early. Check the raw claim value — this tool shows both the human-readable date and the raw timestamp so you can spot unit mismatches instantly.
Does the tool support HS256, RS256, and ES256 verification?
Yes. HS256, HS384, and HS512 are verified with a shared secret. RS256, RS384, and RS512 are verified with an RSA public key in PEM format, and ES256/ES384/ES512 with an EC public key in PEM format. For asymmetric algorithms you never need the private key — verification only requires the public key.
Can I decode a JWT that has no signature or an "alg: none" header?
This tool will still decode the header and payload of any three-part token, but if the algorithm is none or the signature is empty the verification step will report INVALID. Accepting unsigned or alg:none tokens is a serious security vulnerability, so a good debugger always flags them.