JWT signature verifier (HS256, RS256, ES256)
Check a JWT’s signature with an HMAC secret, JWK or PEM public key, and its exp and nbf claims at a time you choose, on your device.
A clear answer. Here’s how.
Splits the compact serialisation (RFC 7515 section 7.1), decodes the Base64url header and payload, and verifies the signature over “header.payload” with the browser’s Web Crypto API: HS256/384/512 are HMAC with SHA-2 (RFC 7518 section 3.2), RS256/384/512 are RSASSA-PKCS1-v1_5 (section 3.3), PS256/384/512 are RSASSA-PSS with a salt as long as the hash (section 3.5), ES256/384/512 are ECDSA on P-256, P-384 and P-521 with the signature as R and S side by side (section 3.4), and EdDSA is Ed25519 (RFC 8037). Keys may be an HMAC secret, a JWK or JWK Set (chosen by kid), or a PEM SubjectPublicKeyInfo, PKCS #1 RSA public key or X.509 certificate (only its public key is used). The checks follow RFC 8725: alg none is never accepted as signed, an HMAC algorithm with a public key is refused as the algorithm-confusion attack, the key type and curve must suit the algorithm, unknown critical headers are refused, and short HMAC secrets or RSA keys under 2048 bits are flagged. exp, nbf and iat (RFC 7519 section 4.1) are compared with the time you type, with optional leeway; the clock is never read. Encrypted JWE tokens, certificate chains, revocation and the meaning of iss, aud or custom claims are not checked.
How this is checked
5 reference checks passed These 5 cases were run when this page was built, on 20 October 2026, and all reproduce within the stated tolerance. The same cases are part of the automated tests that run on every change to Toolmoz. Engine version 1.
See the checks and where each expected answer comes from
Case 1
- Inputs
- JWT (compact JWS) eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXkKey {"kty":"oct","k":"AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow"}
- Expected, and what Toolmoz gave
- Signature expected Valid, Toolmoz ValidAlgorithm expected HS256, Toolmoz HS256
- Where the expected answer comes from
- RFC 7515 appendix A.1: the HS256 JWS with the oct JWK given there validates (section A.1.2)
- Allowed difference
- exact
Case 2
- Inputs
- JWT (compact JWS) eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.cC4hiUPoj9Eetdgtv3hF80EGrhuB__dzERat0XF9g2VtQgr9PJbu3XOiZj5RZmh7AAuHIm4Bh-0Qc_lF5YKt_O8W2Fp5jujGbds9uJdbF9CUAr7t1dnZcAcQjbKBYNX4BAynRFdiuB--f_nZLgrnbyTyWzO75vRK5h6xBArLIARNPvkSjtQBMHlb1L07Qe7K0GarZRmB_eSN9383LcOLn6_dO--xi12jzDwusC-eOkHWEsqtFZESc6BfI7noOPqvhJ1phCnvWh6IeYI2w9QOYEUipUTI8np6LbgGY9Fs98rqVt5AXLIhWkWywlVmtVrBp0igcN_IoypGlUPQGe77RwKey {"kty":"RSA","n":"ofgWCuLjybRlzo0tZWJjNiuSfb4p4fAkd_wWJcyQoTbji9k0l8W26mPddxHmfHQp-Vaw-4qPCJrcS2mJPMEzP1Pt0Bm4d4QlL-yRT-SFd2lZS-pCgNMsD1W_YpRPEwOWvG6b32690r2jZ47soMZo9wGzjb_7OMg0LOL-bSf63kpaSHSXndS5z5rexMdbBYUsLA9e-KXBdQOS-UTo7WTBEMa2R2CapHg665xsmtdVMTBQY4uDZlxvb3qCo5ZwKh9kG4LT6_I5IhlJH7aGhyxXFvUK-DWNmoudF8NAco9_h9iaGNj8q2ethFkMLs91kzk2PAcDTW9gb54h4FRWyuXpoQ","e":"AQAB"}
- Expected, and what Toolmoz gave
- Signature expected Valid, Toolmoz ValidAlgorithm expected RS256, Toolmoz RS256
- Where the expected answer comes from
- RFC 7515 appendix A.2: the RS256 JWS validates with the public part (n, e) of the RSA JWK given there (section A.2.2)
- Allowed difference
- exact
Case 3
- Inputs
- JWT (compact JWS) eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.DtEhU3ljbEg8L38VWAfUAqOyKAM6-Xx-F4GawxaepmXFCgfTjDxw5djxLa8ISlSApmWQxfKTUJqPP3-Kg6NU1QKey {"kty":"EC","crv":"P-256","x":"f83OJ3D2xF1Bg8vub9tLe1gHMzV76e8Tus9uPHvRVEU","y":"x_FEzRu9m36HLN_tue659LNpXW6pCyStikYjKIWI5a0"}
- Expected, and what Toolmoz gave
- Signature expected Valid, Toolmoz ValidAlgorithm expected ES256, Toolmoz ES256
- Where the expected answer comes from
- RFC 7515 appendix A.3: the ES256 JWS validates with the P-256 key (x, y) given there (section A.3.2)
- Allowed difference
- exact
Case 4
- Inputs
- JWT (compact JWS) eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXkKey {"kty":"oct","k":"AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow"}Check exp, nbf and iat at (Unix seconds or ISO time) 1300819381
- Expected, and what Toolmoz gave
- Signature expected Valid, Toolmoz ValidClaims expected Invalid: expired at 2011-03-22T18:43:00Z (1300819380), Toolmoz Invalid: expired at 2011-03-22T18:43:00Z (1300819380)
- Where the expected answer comes from
- RFC 7515 A.1 payload has exp 1300819380 = 2011-03-22 18:43:00 UTC (CPython datetime); RFC 7519 section 4.1.4 requires the check time to be before exp, and 1300819381 is not
- Allowed difference
- exact
Case 5
- Inputs
- JWT (compact JWS) eyJhbGciOiJub25lIn0.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.Key {"kty":"oct","k":"AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow"}
- Expected, and what Toolmoz gave
- Signature expected Refused, Toolmoz Refused
- Where the expected answer comes from
- RFC 7515 appendix A.5 Unsecured JWS (alg none, empty signature); RFC 8725 section 3.1: none must not be accepted as a signed token
- Allowed difference
- exact
What this shows: the engine reproduces independently worked values for these cases. It does not prove every possible input is right. To test an answer you were given, see how to check a number; to see what is and is not checked across Toolmoz, see the accuracy ledger.