Verify the signature of a JSON Web Token (JWT)
- Dashboard
- Documentation
- API
Why verify a JWT's signature?
A JSON Web Token (JWT) breaks down into three parts separated by dots:
header.payload.signature. Decoding a JWT just means reading the first two
parts (which are Base64URL). Anyone can do it, and anyone can build a JWT with the
payload of their choice. What makes a JWT trustworthy is only the
signature: without verification, accepting a JWT is like letting in anyone
who claims to be someone, without asking for ID.
This tool verifies the signature of a JWT against a key. It does not just decode: it recomputes the signature from the header, the payload and your key, then compares it with the token's signature. If the two match, the token is authentic. Otherwise, it was forged, modified, or signed with another key.
Verification is the cornerstone of any architecture that uses JWTs for
authentication or authorisation: without a valid signature, the payload can lie.
An attacker who modified "role":"user" to "role":"admin" would have no
trouble doing so if the server only checked the token's format and not its signature.
Common algorithms
The JWT specification (RFC 7518, JSON Web Algorithms) defines several algorithm families. Here are the most-used in production:
- HMAC (HS256, HS384, HS512): symmetric signature based on HMAC-SHA. The same secret key is used to sign and to verify. Simple to set up, performant, but any party able to verify the token is also able to issue one. Suited to scenarios where the issuer and the verifier are the same team or the same service.
- RSA (RS256, RS384, RS512): asymmetric signature. The private key signs, the public key verifies. Ideal when the issuer and the verifiers are distinct entities (OAuth2, OpenID Connect, identity federation). It is the preferred algorithm of most public identity providers.
- ECDSA (ES256, ES384): asymmetric signature on elliptic curves. Same logic as RSA (private key to sign, public key to verify) but with more compact keys and signatures for an equivalent security level. Increasingly widespread in modern architectures.
How to provide the key
The expected key format depends on the algorithm declared in the JWT header:
- HS256, HS384, HS512: the key is a secret string.
It is the secret shared with the issuer, often stored in an environment variable like
JWT_SECRET. No special formatting, just the raw value. - RS256, RS384, RS512: the key is an RSA public key in PEM format,
starting with
-----BEGIN PUBLIC KEY-----and ending with-----END PUBLIC KEY-----. Keep the line breaks as is, otherwise OpenSSL refuses to parse it. - ES256, ES384: the key is an ECDSA public key in PEM format, on the matching curve (P-256 for ES256, P-384 for ES384).
Example of an expected RSA public key
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxe...
...vQIDAQAB
-----END PUBLIC KEY-----
How does verification work?
Our server reproduces exactly the operation the issuer performed:
- It splits the JWT into header, payload and signature.
- It concatenates
base64url(header) + "." + base64url(payload). - For HMAC, it computes an HMAC-SHA-256/384/512 with your secret key, then compares with the
received signature using
hash_equals(constant-time comparison to avoid timing attacks). - For RSA, it calls
openssl_verifywith your public key in PEM format.
Use cases
- API authentication debugging: you get a 401, check whether your token is indeed signed with the expected key.
- Validating a token received from a provider: a partner (Auth0, Keycloak, Cognito, Okta) sends you JWTs signed with RS256; you want to confirm they really come from them using their public key.
- Security audit: check that a third-party service correctly signs its tokens with a robust algorithm, and not in HS256 with a weak secret.
- Manual tests: check that a JWT generated by your code passes verification with the provided public key.
- Quick verification of a received token: during integration of an SSO or a partner API, check in seconds that the signature/key chain works before writing a single line of code.
How to use the tool
- Paste the full JWT (the three parts separated by dots).
- Provide the key matching the algorithm in the header:
- For HS256, HS384 or HS512, the key is the shared secret
string with the issuer. It is a free string, often stored in an
environment variable like
JWT_SECRET. - For RS256, RS384 or RS512, the key is the public key in PEM
format, starting with
-----BEGIN PUBLIC KEY-----and ending with-----END PUBLIC KEY-----.
- For HS256, HS384 or HS512, the key is the shared secret
string with the issuer. It is a free string, often stored in an
environment variable like
- Launch verification. The tool displays the status (valid or invalid) and the decoded payload.
Common pitfalls to avoid
- Algorithm "none": the spec allows
alg: none, meaning "no signature". A classic flaw is to build a token with this header hoping that the server will accept it. Our tool systematically rejects tokens withalg: none. - HMAC vs RSA confusion (algorithm confusion): an attacker changes the
RS256algorithm toHS256and signs the payload with the RSA public key used as an HMAC secret. If the server does not enforce the algorithm, it accepts the token. Always lock the expected algorithm server-side. - HMAC secrets hard-coded: a secret committed to a Git repository makes the trust of all tokens void. Store secrets in environment variables or an application vault.
- Public key vs private key: to verify an RSA or ECDSA-signed JWT, provide the public key, never the private one. The private one only serves to sign and must never leave the issuer.
- Ignored expiry: a valid signature on an expired token must
never be accepted. Remember to check
expandnbf. - Unchecked audience: a token intended for API A should not be accepted
by API B. Check the
audclaim.
Temporal claims: exp and nbf
Beyond the signature, a valid JWT must also respect its temporal constraints:
- exp (expiration): the token is no longer valid after this date.
- nbf (not before): the token is not yet valid before this date.
Our tool explicitly flags when a token is expired or not yet valid, even if its signature is correct. This matters: a valid signature on an expired token must never be accepted in production.
Difference with our JWT decoder
Our JWT decoder just decodes the header and payload parts to make them readable. It performs no verification of the signature and does not ask for a key. Use it to quickly inspect a token's content. Use the JWT verifier (this page) as soon as you need to prove that a token is authentic. To build a signed JWT for testing purposes, use our JWT builder.
Frequently asked questions
Why RS256 rather than HS256?
With HS256, issuer and verifier share the same secret: any verifier can therefore issue tokens. It is manageable when you control both ends. As soon as you talk about a single identity provider with several consuming services, switch to RS256: the issuer keeps the private key, the public key is distributed to every API that must verify. No consuming API can then forge tokens.
How do I retrieve the public key of an identity provider (IdP)?
Most IdPs expose a standardised JWKS endpoint (for example
https://example.com/.well-known/jwks.json). This endpoint returns a JSON containing
the active public keys. You can convert the JWK entry matching the kid in
your JWT header to a PEM key via the openssl command or via a JWKS
library in your stack (for example jose-jwt, jwks-rsa).
What if verification fails?
First, check the algorithm: a token signed in HS256 cannot be verified with an RSA key, and
vice versa. Then check the key: a stray whitespace, a missing line break in a PEM key,
or an HMAC secret slightly different from the one used by the issuer
are enough to make verification fail. If the IdP rotated its key, your
kid may point to a key you no longer have.
What is JWKS?
JWKS (JSON Web Key Set, RFC 7517) is a JSON format that describes a set of
public keys. Each key is identified by a kid (key ID) and the JWT to verify
references this kid in its header. The mechanism allows the IdP to rotate its
keys without breaking verifiers: they simply query the JWKS endpoint to retrieve the
key matching the kid of the received token.
How do I generate an RSA key pair to sign my JWTs?
With OpenSSL: openssl genrsa -out private.pem 2048 then
openssl rsa -in private.pem -pubout -out public.pem. The private key signs on the
issuer side, the public key verifies on the consumer side. For new services, prefer 3072 or
4096 bits.
Should the JWT be encrypted in addition to being signed (JWE)?
A signed JWT (JWS) guarantees integrity and authenticity, but the payload remains readable by anyone who gets it. If the token contains sensitive data (internal identifiers, detailed rights, personal data), consider the JWE format (JSON Web Encryption) which encrypts the payload on top of signing it.
Example request
curl -X POST https://cdrn.fr/api/v1/tools/jwt-verifier/execute \
-H "Content-Type: application/json" \
-d '{"token":"...","key":"..."}'
Input schema
| Field | Type | Required | Default |
|---|---|---|---|
token |
text | ✓ | – |
key |
text | ✓ | – |
Endpoints
GET https://cdrn.fr/api/v1/tools- lists every available toolGET https://cdrn.fr/api/v1/tools/jwt-verifier- returns the schema for this toolPOST https://cdrn.fr/api/v1/tools/jwt-verifier/execute- runs this tool with a JSON payload