How to use the JWT Decoder and Verifier
- Paste the token, with or without the "Bearer " prefix.
- Read the header, the claims and when the token expires.
- Enter the shared secret, or paste the public key, certificate or JWKS.
- Read whether the signature verifies and what the checks found.
- To test an API, create a signed HS256 token from your own claims.
What a JWT decoder does
A JWT (JSON Web Token, RFC 7519) is three base64url strings joined by dots: a header naming the signing algorithm, a payload of claims such as sub and exp, and a signature over the first two. Decoding only reverses the base64url, so anyone holding a token can read every claim in it; verifying checks the signature with the issuer's secret or public key, and only a verified token proves who issued it and that nobody changed it.
That difference is where most JWT bugs live. In the Node.js jsonwebtoken package, jwt.decode() checks nothing, while jwt.verify() checks the signature and the expiry. An API that reads claims from a decoded but unverified token trusts whatever the caller wrote.
How the decoder works
The token is split on its dots, each part is base64url-decoded strictly (a +, / or stray character is reported with its position), and the header and payload must be UTF-8 JSON objects. The signature is checked with the browser's WebCrypto, with the algorithm taken from the header and the key you supply. A five-part token is an encrypted JWE: its header is readable, its payload is not without the recipient's private key.
The signing algorithms
| alg | Key | Notes |
|---|---|---|
| HS256, HS384, HS512 | A shared secret | HMAC (RFC 7518 §3.2). Whoever can verify can also sign. The secret should be at least as long as the hash: 32 bytes for HS256 |
| RS256, RS384, RS512 | RSA public key | PKCS#1 v1.5 signatures; keys of 2048 bits or more |
| PS256, PS384, PS512 | RSA public key | RSA-PSS, salt as long as the hash |
| ES256, ES384, ES512 | EC key on P-256, P-384 or P-521 | The signature is raw r and s (64, 96 or 132 bytes), not DER |
| EdDSA | Ed25519 key | RFC 8037; short keys and signatures |
| none | Nothing | An unsigned token. Servers must reject it |
The key can be pasted as a PEM public key, a PKCS#1 RSA PUBLIC KEY, an X.509 certificate, a single JWK, or a whole JWKS such as the one an identity provider publishes at /.well-known/jwks.json; with a JWKS the key whose kid matches the token's header is used.
Claims and clock skew
exp (expiry), nbf (not before) and iat (issued at) are NumericDate values: seconds since 1970, not milliseconds. The decoder shows each as a UTC time and relative to now, and applies a clock-skew allowance (60 seconds by default) the way verification libraries do, because two servers' clocks are never exactly equal. iss and aud say who issued the token and who it is for; a verifier should check both.
Worked example: verify on the command line
Decode a payload with standard tools (base64url needs its alphabet swapped and its padding restored first):
b64url() { s=$(tr '_-' '/+'); while [ $(( ${#s} % 4 )) -ne 0 ]; do s="$s="; done; printf '%s' "$s" | base64 -d; }
TOKEN='eyJhbGciOi...'
printf '%s' "$TOKEN" | cut -d. -f2 | b64url; echoCheck an RS256 signature with OpenSSL and the issuer's public key:
printf '%s' "$TOKEN" | cut -d. -f1,2 | tr -d '\n' > signed.txt
printf '%s' "$TOKEN" | cut -d. -f3 | b64url > signature.bin
openssl dgst -sha256 -verify public.pem -signature signature.bin signed.txtVerified OK means the token is genuine. ES256 signatures need converting to DER before openssl dgst accepts them, which is one reason a browser check is handier.
Common errors and how to fix them
- invalid signature: the secret or key is wrong. Check whether the secret is meant to be base64-decoded first, whether the issuer rotated its keys (the
kidwill not be in the JWKS you have), and whether the token was copied whole. - jwt expired:
exphas passed. Refresh the token; if it happens only on one server, compare clocks withtimedatectland enable NTP. - jwt malformed: not three parts. Quotes, a
Bearerprefix or line breaks from copying are the usual cause. - invalid algorithm: the token's
algis not one the server allows. Good: pin the expected algorithm, so an attacker cannot switch RS256 to HS256 and sign with your public key as the secret. - ES256 signature fails everywhere: the signer wrote a DER signature (usually 70 to 72 bytes) instead of the 64-byte raw form JWS requires.
A short security checklist
RFC 8725 collects the lessons: pin the algorithms you accept and refuse none; check exp, nbf, iss and aud; never fetch a key from a jku or x5u URL the token itself supplies; keep access tokens short-lived; and never put secrets in the payload, which anyone can read.
JWT secrets and Shipown
When you deploy a Node.js API with Shipown, its JWT signing secret belongs in the app's environment values, not in the repository; they are sent to the build or deployment machine as needed, as the credentials page explains. To decode the base64 parts by hand, use the base64 decoder.
Frequently asked questions
Is it safe to paste a JWT into an online decoder?
A JWT is a bearer credential: whoever holds an unexpired one can use it. This decoder runs in your browser and sends nothing, but prefer expired or test tokens on any site that sends them to a server.
Can you decode a JWT without the secret?
Yes. The header and payload are only base64url-encoded, so anyone can read them. The secret or public key is needed only to verify the signature.
Why does my JWT say "invalid signature"?
The key does not match the one that signed it: a wrong or base64-encoded secret, a rotated key with a different kid, or a token that was changed or cut short when copied.
What is the difference between HS256 and RS256?
HS256 signs and verifies with one shared secret, so every verifier can also mint tokens. RS256 signs with a private key and verifies with the public key, so verifiers cannot create tokens.
How do I fix "jwt expired"?
Get a new token or refresh it: exp is in the past. If fresh tokens fail too, the server clock is wrong; enable NTP or allow a small clock skew.
What are a JWKS and a kid?
A JWKS is a JSON list of public keys an issuer publishes. The kid in a token header names the key that signed it, so a verifier picks the matching key from the JWKS.