Introduction
A JWT is only trustworthy if its signature checks out. This tool decodes the three-part token (header.payload.signature) and verifies the signature using the Web Crypto API, supporting HS256 (HMAC-SHA256), RS256 (RSA-PKCS1-v1.5-SHA256), and ES256 (ECDSA-P-256-SHA256). Paste a token, provide the shared secret or public key, and the result updates instantly. Everything runs in your browser. No token or key is sent anywhere.
What this tool does
- Decode a JWT into its header and payload JSON, displaying the algorithm, token type, and registered claims (iat, nbf, exp) with human-readable timestamps
- Verify HS256 signatures by recomputing HMAC-SHA256 over the signing input (header.payload) and comparing it to the token's signature in constant time
- Verify RS256 signatures using an RSA public key in PEM (SPKI) or JWK format via the Web Crypto API RSASSA-PKCS1-v1.5 algorithm
- Verify ES256 signatures using an ECDSA P-256 public key, converting the raw r||s signature format to DER before calling Web Crypto verify
- Auto-detect the algorithm from the JWT header and switch the verification mode accordingly
- Run entirely client-side using the browser's native Web Crypto API, so secrets and public keys never leave the device
How this tool works
The tool splits the JWT on the two dot characters to extract the header, payload, and signature segments. Each segment is base64url-decoded (converting `-` to `+` and `_` to `/`, then padding with `=`). The header and payload are parsed as JSON to display the algorithm, token type, and registered claims.
For HS256, the tool imports the shared secret as a raw HMAC key using `crypto.subtle.importKey`, then calls `crypto.subtle.sign` to compute HMAC-SHA256 over the UTF-8 encoded signing input (`header.payload`). The computed signature is compared to the decoded token signature using a constant-time comparison function that XORs each byte and accumulates differences, preventing timing attacks.
For RS256, the tool accepts either a PEM-encoded SPKI public key or a JWK JSON object. It imports the key with the RSASSA-PKCS1-v1.5 algorithm and SHA-256 hash, then calls `crypto.subtle.verify` directly. For ES256, the same import flow applies, but the raw r||s signature (64 bytes for P-256) must be converted to DER-encoded ASN.1 format before Web Crypto can verify it. The tool handles this conversion by encoding the two 32-byte halves as ASN.1 integers with proper leading-zero handling.
The tool also checks the `exp`, `nbf`, and `iat` claims, converting Unix timestamps to ISO 8601 strings and flagging expired tokens.
How JWT signatures work (RFC 7519, 7515, 7518)
JSON Web Tokens are defined in RFC 7519. A JWT consists of three base64url-encoded parts separated by dots: a JOSE header, a payload (set of claims), and a signature. The header specifies the signing algorithm via the `alg` field. The signature is computed over the signing input, which is the base64url-encoded header concatenated with a dot and the base64url-encoded payload.
The signing algorithms themselves are defined in two companion RFCs. RFC 7515 specifies JSON Web Signature (JWS), the structure that wraps the header, payload, and signature. RFC 7518 defines JSON Web Algorithms (JWA), which lists the specific algorithms identified by the `alg` header value.
HS256 uses HMAC with SHA-256, meaning the same secret is used to sign and verify. This is symmetric: the verifier must possess the secret. RS256 uses RSA PKCS#1 v1.5 signature with SHA-256, where the signer holds the private key and the verifier holds the corresponding public key. ES256 uses ECDSA on the P-256 curve with SHA-256. JWT signatures for ES256 use the raw concatenation of the r and s values (64 bytes total), not the DER-encoded format that some libraries produce.
A verified signature proves integrity and authenticity: the token was signed by the holder of the key and has not been modified. It does not prove freshness unless you also check the `exp` (expiration) and `nbf` (not before) claims. To create or decode tokens, see the JWT Encoder and JWT Decoder. For key format conversion, use the JWK Converter.
How to use this tool
- Paste your JWT into the input field. The tool splits it on dots and decodes the header and payload automatically
- The tool auto-detects the algorithm from the header's `alg` field. You can also manually select HS256, RS256, or ES256
- For HS256, enter the shared secret in the key field. For RS256 or ES256, paste a PEM public key (starting with `-----BEGIN PUBLIC KEY-----`) or a JWK JSON object
- The verification runs immediately as you type. The result panel shows VALID or INVALID along with the computed signature in hex
- Check the decoded header and payload for the `exp` claim. The tool flags expired tokens automatically
- Review the verification steps shown in the output to trace the process from token splitting through signature comparison
Real-world examples
Verifying an HS256 token from a Node.js backend
Your Node.js API signs tokens with `jsonwebtoken.sign(payload, secret)`. Copy the resulting token, paste it into the tool, select HS256, and enter the same secret string. The tool computes HMAC-SHA256 over the signing input and compares it to the token's signature. If they match, the signature is valid and the payload has not been tampered with.
Verifying an RS256 token with a JWKS public key
An Auth0 or AWS Cognito token uses RS256. Fetch the public key from the provider's JWKS endpoint as a JWK JSON object, paste it into the key field, and the tool imports it via `crypto.subtle.importKey('jwk', ...)`. The verification confirms the token was signed by the identity provider's private key.
Debugging an expired token
Paste a token and notice the output shows `Expiration (exp): 2024-01-15T12:00:00.000Z` with `Token status: EXPIRED`. Even if the signature is valid, the token should be rejected by your application logic. The tool surfaces this so you can distinguish signature failures from expiration failures.
ES256 signature with a PEM public key
An ECDSA P-256 token carries a 64-byte raw signature. The tool converts this to DER format internally before calling Web Crypto verify. Paste the PEM public key from your signing service, and the tool handles the r||s to DER conversion automatically.
Comparison with similar methods
| Method | Complexity | Typical use |
|---|---|---|
| HS256 | Symmetric, HMAC-SHA256, shared secret | Internal APIs, single-party tokens |
| RS256 | Asymmetric, RSA 2048+, public key verify | OAuth2/OIDC providers, multi-party |
| ES256 | Asymmetric, ECDSA P-256, public key verify | Modern OIDC, shorter signatures than RSA |
| none | No signature, insecure | Never use in production (attack vector) |
Limitations or considerations
This tool verifies signatures only. It does not validate custom claims, audience (`aud`), issuer (`iss`), or scope. Your application must perform those checks separately after signature verification.
The tool supports HS256, RS256, and ES256. It does not handle PS256 (RSA-PSS), EdDSA (Ed25519), or other algorithms. If the token header specifies an unsupported algorithm, the tool shows an error.
For HS256, the shared secret is entered as a text string. If your backend uses a base64-encoded secret, decode it first and paste the raw bytes, or the HMAC will not match.
The tool does not fetch JWKS from a remote endpoint. You must paste the public key or JWK manually. For automated JWKS fetching and caching, use a library like `jose` or `jsonwebtoken` in your server code.
Frequently asked questions
What is the difference between HS256 and RS256?
HS256 is symmetric: the same secret signs and verifies the token. RS256 is asymmetric: a private key signs, and a public key verifies. RS256 is preferred in multi-party systems like OAuth2 because the verifying party never sees the signing key.
Why does my ES256 token fail verification in some libraries but work here?
JWT ES256 signatures use the raw r||s format (64 bytes for P-256), per RFC 7518. Some cryptographic libraries expect DER-encoded signatures. This tool converts the raw format to DER before calling Web Crypto, so it handles JWT-specific ES256 signatures correctly.
Can someone tamper with a JWT by changing the header algorithm to 'none'?
The `none` algorithm means no signature is present. RFC 7515 Section 4.1.1 requires implementations to reject tokens with `alg: none` unless explicitly configured otherwise. This tool does not support `none` and will show an error if the header specifies it.
Does a valid signature mean the token is safe to accept?
No. A valid signature proves the token was signed by the key holder and has not been modified. You must still check expiration (`exp`), not-before (`nbf`), audience (`aud`), and issuer (`iss`) claims before trusting the payload.
Is it safe to paste my secret or public key into this tool?
Yes. All verification runs in your browser using the Web Crypto API. The secret or key is never transmitted to a server. The tool has no backend. However, avoid pasting secrets into tools you do not control, and always verify the page is served over HTTPS.
Conclusion
JWT signature verification is the first step in trusting a token, but it is not the last. This tool handles the cryptographic verification for HS256, RS256, and ES256 using the browser's native Web Crypto API, with no data leaving your device. For creating tokens, use the JWT Encoder. For decoding without verification, see the JWT Decoder. To convert between PEM, DER, and JWK key formats, use the JWK Converter.