A JWT can be decoded in seconds, but decoding is not validation. This guide provides a repeatable workflow for inspecting claims safely, checking expiration and time skew, confirming issuer and audience, validating signatures, and diagnosing the API errors that commonly cause rejected tokens.
Overview
JSON Web Tokens (JWTs) are compact tokens used to carry signed claims between systems. They often appear in OAuth 2.0 and OpenID Connect integrations, service-to-service APIs, and browser or mobile application sessions. A JWT normally has three Base64URL-encoded parts separated by periods:
- Header: describes token metadata, including the signing algorithm (
alg) and, in some systems, a key identifier (kid). - Payload: contains claims such as the subject, issuer, audience, and time-based values.
- Signature: allows a verifier to detect whether the signed content was changed and whether it was produced with an accepted key.
Decoding the first two parts only reveals their contents. It does not prove that the token is authentic, unmodified, intended for your API, or currently valid. A JWT decoder is therefore useful for investigation, but it is not a replacement for trusted verification in application code.
Use the following anatomy reference when debugging:
| Field | Location | What to check |
|---|---|---|
alg | Header | It matches an algorithm explicitly allowed by the verifier; never accept an algorithm solely because the token requests it. |
kid | Header | The key identifier maps to the expected issuer's key set and is handled safely during key rotation. |
iss | Payload | The issuer exactly matches the configured identity provider or authorization server. |
aud | Payload | The token is intended for this API or service. The value may be a string or, depending on the implementation, a list. |
sub | Payload | The subject identifies the user, client, or principal according to the provider's convention. |
exp | Payload | The expiration time has not passed. JWT time claims are commonly represented as NumericDate values in seconds since the Unix epoch. |
nbf | Payload | The token is not being used before its permitted start time. |
iat | Payload | The issuance time is plausible and consistent with the authentication flow; it is not, by itself, proof of validity. |
| Scopes or roles | Payload | The claims grant the required permission, and your API maps them to authorization rules correctly. |
Claim names and formats vary by identity provider. Treat provider documentation and your own verifier configuration as the source of truth rather than assuming that a familiar claim has identical meaning everywhere.
Checklist by scenario
When a token is rejected as malformed
- Confirm that the value sent to the API is the complete token, with all three segments present and separated by two periods.
- Check the authorization header format. For a bearer token, the scheme and token should be separated by whitespace, without surrounding quotation marks or an accidental trailing character.
- Check for line breaks, URL decoding, JSON escaping, or shell interpolation that may have changed the token during transport.
- Decode the header and payload locally or with an approved inspection tool. A Base64URL decoding error usually points to truncation or altered characters, not an invalid claim.
- Compare the token type expected by the endpoint with the token you obtained. An access token and an identity token may both look like JWTs but serve different purposes.
When the token is expired or not active
- Read
exp,nbf, andiatas timestamps in the unit expected by the JWT library. Do not compare a seconds-based value directly with a milliseconds-based system clock. - Compare the token time with the server's clock, not only your laptop's clock. Inspect time synchronization and timezone-independent system time on the API host, container, and identity service.
- Allow only a small, deliberately configured clock-skew tolerance where your security model permits it. A large tolerance can extend the effective lifetime of a token.
- Determine whether the client is reusing a cached token after expiration. During testing, obtain a fresh token instead of repeatedly retrying the same value.
When signature validation fails
- Identify whether the token uses a symmetric algorithm, such as one requiring a shared secret, or an asymmetric algorithm requiring a public key.
- Confirm that the verifier is using the key belonging to the expected issuer and environment. Development and production keys should not be mixed.
- Check the
kidvalue and key-set lookup behavior, especially during a signing-key rotation. A missing or unknown key identifier should fail closed. - Configure an explicit algorithm allowlist in the library. Do not let the token choose a weaker or unintended verification method.
- Verify the exact signed input. Re-serializing the header or payload before verification can change the bytes and invalidate a legitimate signature.
When authentication succeeds but authorization fails
- Confirm that authentication middleware ran before authorization middleware.
- Compare the token's
audandisswith the API's configured values. - Inspect scopes, roles, groups, and permissions using the provider's documented claim conventions. A role may be an array in one integration and a space-delimited scope string in another.
- Check whether the endpoint requires a user token, client-credentials token, or a different scope.
- Review the API's mapping logic and case sensitivity. A correctly signed token can still lack the permission required for a resource.
For a broader test plan covering JWT, OAuth, API keys, and authorization failures, see the API Authentication Testing Guide.
What to double-check
Decoding versus trusted verification
Local decoding answers, “What data does this token claim to contain?” Verification answers, “Was this token signed by an accepted issuer, has its content remained unchanged, and is it valid for this service now?” Keep those questions separate in code, documentation, and incident notes.
Never authorize a request because a decoded payload contains an expected role or because the token's alg field looks familiar. The application must verify the signature with a trusted key, enforce the expected issuer and audience, apply time checks, and then evaluate permissions. If you use an online developer utility or JWT decoder, redact or avoid real production tokens. A token can grant access even when it appears to contain no obvious password.
Issuer, audience, and environment
A valid signature does not make a token valid for every service. Check the exact issuer URL, including the configured tenant or realm where applicable, and verify the intended audience. Confirm that the API, client, and identity provider all refer to the same environment. A token issued for a staging API should not be accepted by a production API simply because both use the same identity platform.
Key rotation and operational evidence
Record the error category, issuer, audience, key identifier, and time window without logging the complete token. Logs should help distinguish malformed input, expired credentials, unknown keys, and insufficient permissions while avoiding credential exposure. Review key discovery, caching, and rotation behavior in the same deployment path as the API. If secrets or signing material are involved, use a controlled rotation process; the cloud secrets management guide provides related operational guidance.
Common mistakes
- Confusing Base64URL with encryption: encoded claims are readable by design. Do not put secrets or sensitive data in a token unless the design explicitly protects them.
- Trusting decoded claims: parsing is not signature verification and does not establish identity.
- Accepting any algorithm: verification should be constrained by server-side configuration, not by untrusted header input.
- Using the wrong token: an ID token may describe an authenticated user, while an access token is intended for a resource server. Follow the identity provider's documented flow.
- Ignoring audience validation: a token can be correctly signed and still be intended for another service.
- Comparing timestamps incorrectly: seconds and milliseconds, as well as client and server clocks, are frequent sources of false expiration errors.
- Logging full credentials: request dumps, exception traces, browser storage exports, and CI logs can expose reusable tokens.
- Returning overly detailed errors: internal logs can contain diagnostic context, while external responses should reveal only what clients need to correct the request.
If a JWT is used in a containerized or Kubernetes workload, include token handling in the deployment review rather than treating it as only an application concern. The Kubernetes deployment readiness checklist can complement that review.
When to revisit
Revisit this checklist before a seasonal planning cycle, identity-provider migration, major API release, or authentication configuration change. It should also be reviewed whenever your JWT library, key-discovery mechanism, authorization middleware, or deployment workflow changes. Library defaults and provider claim conventions can evolve, so confirm examples and verification settings against the versions and documentation used by your team.
Before closing a JWT incident or integration task, capture a short, non-sensitive record:
- the endpoint and environment tested;
- the expected issuer, audience, and algorithm policy;
- the observed error category and approximate time;
- whether the token was malformed, expired, outside its validity window, signed by an untrusted key, or unauthorized;
- the corrective change and the test that confirmed it.
Finally, test both success and failure paths: a valid token, an expired token, an incorrect audience, an unknown issuer, a changed signature, an insufficient scope, and a missing authorization header. This makes JWT debugging a repeatable developer workflow rather than an exercise in guessing. For related work across CI/CD and release verification, see the CI/CD Pipeline Design Guide.