JWT validation: signatures, claims and the key you actually trust

Work through a token-verification decision using issuer, audience, expiry and an independently trusted key.

A decoded JSON Web Token can look convincing. It may contain an email address, an administrator role and an expiry time, all neatly formatted by a tool. None of those fields becomes trustworthy merely because the token can be decoded. A reliable validation decision starts with the application’s expected issuer, audience, signing method and trusted key.

This guide follows a fictional API receiving a signed token from its identity provider. The API needs to decide whether that token is intended for this service and whether the claims can be used now. The example is about validation design and troubleshooting. It does not require copying a live access token into a public discussion or exposing a signing secret to another service.

Separate the encoded structure from authenticated meaning

A compact signed JWT commonly has three dot-separated segments: a protected header, a payload and a signature. The first two segments contain Base64url-encoded data. Decoding them is a reversible representation change, not signature verification. A token can be structurally readable even when its signature is invalid or its claims are inappropriate for the application.

The protected header can name an algorithm and a key identifier. Those values arrive with the untrusted token. The server must compare them with its own allowed configuration rather than letting the token choose any algorithm or key location it prefers. A key identifier can help select among already trusted keys; it is not independent proof that the selected key belongs to the expected issuer.

The JWT inspector can decode a compact token and optionally verify supported HS256 or RS256 signatures using a key you supply. That result is a diagnostic observation. Your application still needs its own claim-validation and authorisation rules.

Write the validation contract before inspecting a token

A fictional orders API’s validation contract
CheckExpected value or ruleWhy it is needed
IssuerThe configured identity provider identifierRejects tokens from another security domain
AudienceThe orders API identifierPrevents a token for another service being reused here
AlgorithmA server-configured allowlistAvoids accepting a method selected only by the token
Verification keyA key obtained through the trusted issuer configurationConnects a valid signature to the intended signer
Time claimsExpiry and not-before rules with defined clock toleranceConstrains the period of acceptance
Token purposeThe expected token type and application usageKeeps tokens from different workflows separate
AuthorisationPermissions required for this operation and resourceA valid identity token is not blanket access

This contract belongs in application configuration and tests. It should not be inferred from whichever token happens to arrive first. A troubleshooting session becomes much clearer when “signature valid” and “accepted by this API” are treated as separate decisions with documented reasons.

Read a claim set against the intended audience

{
  "iss": "https://identity.example.com/",
  "aud": "orders-api",
  "sub": "test-user-42",
  "iat": 1700000000,
  "exp": 1700003600,
  "scope": "orders:read"
}

These are fictional historical values for explanation. The expiry is one hour after the issued-at value. JWT NumericDate values use seconds relative to the Unix epoch, so treating them as JavaScript milliseconds produces an incorrect date. This sample is not a current credential and should not be accepted in a present-day application.

If the token has a valid signature but the receiving service expects billing-api, the audience check should fail. If the orders API receives it for an operation requiring orders:write, the read scope does not grant that operation. Verification establishes the integrity of the signed claim set under the trusted key; the application decides what those claims permit.

Audience can be represented as a string or an array under JWT rules. Use a maintained library that handles the permitted representation and compare against the configured service identifier. Avoid substring checks that accept an audience merely because its text contains the expected name.

Distinguish shared secrets from public verification keys

HS256 uses HMAC with a shared secret. A party holding that secret can generally create signatures as well as verify them. Distributing the same HMAC secret to several independent services expands the set of parties able to mint accepted tokens. That trust arrangement should be deliberate.

RS256 uses an asymmetric key pair. The private key signs, and the public key verifies. A public verification key is not confidential in the same way as the private key, but its authenticity still matters. An attacker can provide a public key that verifies tokens they signed; the mathematics does not connect that key to your intended identity provider automatically.

Obtain verification keys through the issuer configuration or another authenticated trust process. If the application retrieves a key set, constrain its source and handle rotation deliberately. Do not follow arbitrary token-supplied URLs as if they were trusted configuration. Separate allowed algorithms by key type so that a key cannot be reinterpreted under an unintended signing method.

Verify the original signed bytes

For a compact JWS, the signature concerns the original encoded header and payload segments joined by a period. Decoding the JSON, changing spacing and serialising it again creates a different byte sequence. A diagnostic should preserve the original segments when verifying rather than reconstructing a visually equivalent document.

This is why editing a claim in a decoder does not preserve the original signature. It is also why a token copied with extra whitespace, missing characters or a changed Base64url segment can fail verification. Inspect copy and transport problems before concluding that the issuer’s key rotation is broken.

Use test tokens and disposable credentials when reproducing a signature failure. The local inspector omits the supplied verification key from report exports, but a decoded payload can still contain personal data or identifiers. Review the payload before exporting or sharing the report.

Make time validation explicit

Expiry, not-before and issued-at claims have different meanings. An expiry limits when the token may be accepted under the application’s validation rules. A not-before value constrains the start of acceptance. Issued-at records an issuance time and may support additional application checks, but it is not a replacement for expiry.

Define any clock tolerance narrowly and consistently. A tolerance intended to absorb small clock differences should not quietly become an extension of every session’s useful lifetime. When troubleshooting, compare the validating server’s clock, the token values and the exact tolerance applied.

Also decide which claims are required for the token type. A library may support validation of an expiry when present without requiring that every accepted token contain one. The application’s contract must close that gap where expiry is mandatory. Tests should include missing claims, wrong types and boundary times, not only a single valid token.

Plan rotation and revocation separately

Key rotation changes which signing keys are active and which verification keys remain accepted. Overlap can be necessary for tokens issued shortly before the switch. Track key identifiers, cache behaviour and the intended retirement time so a routine rotation does not become an unexplained outage.

Revocation is a different problem. A self-contained token can remain cryptographically valid after a user signs out unless the system has an additional mechanism to reject it or its short lifetime expires. Depending on the design, that may involve server-side session state, token identifiers, introspection or another revocation strategy.

Do not promise immediate logout merely because a client deletes its local copy. Decide what happens to an already copied token and document the trade-off between stateless acceptance and rapid revocation. The diagnostic tool cannot establish that operational policy from the compact token alone.

Frequently asked questions

Is an ID token interchangeable with an API access token?

No. Tokens issued for authentication and tokens issued for access to an API can have different audiences, claim requirements and validation rules. A familiar subject identifier does not make the token suitable for another purpose. Follow the identity provider’s documented token contract and keep the application’s acceptance rules specific to the endpoint receiving it.

Can a key identifier be used as a filename directly?

It should be treated as untrusted input and matched against a controlled key registry. Avoid allowing it to construct arbitrary filesystem paths or network destinations. Selection should choose among keys the application already knows how to trust, with a defined response when the identifier is unknown.

Can I trust a token if its signature verifies?

Only after connecting the key to the intended issuer and applying the required claim and purpose checks. A valid signature under an arbitrary supplied key proves little about your application’s trust relationship. Authorisation remains a separate decision for the requested operation.

Are JWT payloads encrypted?

A signed compact JWT with readable Base64url header and payload is not encrypted by that encoding. Anyone holding it can usually decode those segments. Encrypted token formats exist, but a three-segment signed token should not be treated as a confidential container.

Why does changing JSON formatting break verification?

The signature covers encoded bytes, not a human interpretation of the claims. Different spacing, member ordering or encoding can produce another signing input. Verify the original token segments and use the decoded representation only for inspection.

What should a regression test reject?

Include an unexpected algorithm, untrusted key, wrong issuer, wrong audience, expired or premature token, missing required claim and inappropriate token purpose. Add authorisation tests for operations the token must not permit. Successful decoding should never be the acceptance condition.

Sources and further reading

50 useful tools · ↑ ↓ to navigate · Enter to open · Esc to close