# How to decode and verify a JWT safely

Decode a JWT locally, select a trusted verification key and expected algorithm, then check issuer, audience and time claims. Understand what a match proves.

Canonical: https://tamperbox.dev/guides/decode-verify-jwt-safely

Updated: 2026-10-18

Reviewed: 2026-10-17

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](https://tamperbox.dev/jwt) 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](https://tamperbox.dev/unix-timestamp) 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:

```json
{"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](https://www.rfc-editor.org/rfc/rfc8725).
