tamper[box]

How to decode and verify a JWT safely

Decoding a token answers what it says. Signature verification and application policy answer different questions. Keep those steps separate when debugging authentication.

Inspect the structure locally

Open JWT Decoder & Verifier and start with a synthetic example. A three-part signed token contains a header, payload and signature. Read the algorithm and claims before editing. This browser tool does not upload the token or automatically retrieve keys named by it.

Choose verification settings independently

Select the expected algorithm from your application's configuration, rather than trusting only the token's alg value. Supply the intended public key or HMAC secret from a trusted source. A matching signature means that key verifies those bytes; it does not identify the correct issuer by itself.

Set the expected issuer and audience. Review expiry and not-before values against the intended policy and clock tolerance. The tool's default algorithm follows the token, so an explicit selection matters when testing algorithm mismatch behavior.

Check time units and edits

JWT NumericDate values use seconds. For example, the synthetic claim exp=1700000000 means 2023-11-14T22:13:20Z. Open Unix Timestamp Converter with seconds selected to inspect it. Milliseconds in an expiry claim can produce a date far in the future.

Changing claims changes the signed bytes. Rebuild or re-sign a test token only for a test environment, then verify the changed token again. An unsigned alg:none token is not evidence of authentication.

Keep application checks in the application

A token can have a matching signature and still be expired, intended for another audience or unacceptable under application policy. This tool does not implement your authorization decisions or decrypt JWE tokens.

Worked example: valid signature, expired claim

Use a synthetic HS256 token with a test-only secret and this payload:

{"iss":"https://issuer.example","aud":"test-api","iat":1792195140,"nbf":1792195140,"exp":1792195200}

At the fixed comparison time 2026-10-17 00:00:30 UTC (1792195230 seconds), expiry was 30 seconds ago. The signature can match while exp fails with zero clock tolerance. With 60 seconds of tolerance, this expiry check passes; the claim table and verdict should agree. The live tool uses your device clock, so the same historical example expires outside that window today.

Changing the expected audience from test-api to production-api makes the audience check fail even with a matching signature. Editing aud in the token changes its signed bytes. If you keep a test HMAC secret entered, the tool can re-sign; that establishes only that your test key signs the new token. Your application still needs its own permitted algorithm, issuer, audience and authorization policy.

These values are a reproducible time-bound example, not a credential or a token accepted by a live service.

Reference

JWT best current practices, RFC 8725.