JWTs are everywhere in modern web applications. They carry authentication claims from an identity provider to your API. They encode session data. They authorize access to specific resources. But a JWT is only trustworthy if you verify its signature.
Decoding a JWT is trivial — base64-decode the payload and you can read the claims. Verifying a JWT requires the secret or public key used to sign it. Without verification, any attacker can forge a token with arbitrary claims.
How JWT Signatures Work
A JWT has three parts separated by dots:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIn0.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
- Header — base64url-encoded JSON:
{"alg":"HS256","typ":"JWT"} - Payload — base64url-encoded JSON:
{"sub":"1234567890","name":"John Doe"} - Signature — computed over header + "." + payload
The signature algorithm is specified in the header's alg field. Common algorithms:
| Algorithm | Type | Key |
|-----------|------|-----|
| HS256 | HMAC-SHA256 | Shared secret |
| HS384 | HMAC-SHA384 | Shared secret |
| HS512 | HMAC-SHA512 | Shared secret |
| RS256 | RSA-SHA256 | Private/public key pair |
| RS384 | RSA-SHA384 | Private/public key pair |
| ES256 | ECDSA-SHA256 | EC private/public key pair |
HMAC (symmetric) tokens
For HMAC algorithms (HS256, HS384, HS512), the same secret is used to sign and verify. The server signs the token at login, stores the secret, and verifies incoming tokens with the same secret. This is simple but requires that every service that verifies tokens has access to the secret.
RSA/EC (asymmetric) tokens
For RSA and ECDSA algorithms, the identity provider signs tokens with a private key and publishes the corresponding public key (often via a JWKS endpoint). Any service can verify tokens using only the public key, without needing access to the private key. This is the preferred approach for distributed systems.
The alg:none Attack
One of the most notorious JWT vulnerabilities involves the alg: "none" header. Some older JWT libraries accepted tokens with alg: none and skipped signature verification entirely. An attacker could modify the payload, set alg to none, remove the signature, and the library would accept the token.
Always verify that the alg field matches what you expect. Reject tokens with alg: none unless you specifically intend to accept unsigned tokens.
Using the DevHexLab JWT Signature Verifier
The verifier lets you test JWT signature verification in the browser without sending tokens to a server.
Verifying an HMAC token
1. Paste your JWT into the token field
2. Select the algorithm (HS256, HS384, or HS512)
3. Enter your secret key
4. Click Verify
The tool shows whether the signature is valid, plus the decoded header and payload.
Verifying an RSA or EC token
1. Paste your JWT into the token field
2. Select the algorithm (RS256, RS384, RS512, ES256, ES384, ES512)
3. Paste your public key in PEM format (begins with -----BEGIN PUBLIC KEY-----)
4. Click Verify
Checking expiration and claims
The verifier also checks the standard registered claims:
- exp — expiration time: is the token expired?
- nbf — not before: is the token valid yet?
- iat — issued at: when was the token issued?
- iss — issuer: who issued the token?
- aud — audience: who is the token intended for?
Security Best Practices
Always verify signatures server-side. The browser-based verifier is for development and debugging. Production code must verify tokens in your backend, never in client-side JavaScript.
Pin the expected algorithm. Do not read the algorithm from the token header and verify with that algorithm. Instead, specify the algorithm you expect and reject tokens using any other algorithm.
Rotate secrets and keys regularly. HMAC secrets and RSA private keys should be rotated periodically. Use key IDs (kid header claim) to support multiple active keys during rotation.
Keep expiration times short. Short-lived tokens (15 minutes) limit the damage if a token is compromised. Use refresh tokens to obtain new access tokens without re-authenticating.
Conclusion
JWT signature verification is a critical security control. A decoded but unverified JWT is not trustworthy. Use the DevHexLab JWT Signature Verifier to inspect and verify tokens during development, and make sure your production code always verifies signatures with a pinned algorithm.