Debugging 401 Errors With JWTs: Reading Claims, Expiry and Signature Problems
How to decode a JSON Web Token, what each standard claim means, and the most common reasons a valid looking token is rejected, including seconds versus milliseconds and clock skew.
Published September 26, 2026 · By Sudip Bhowmick
An API returns 401 and the token in your request looks perfectly fine. JSON Web Tokens fail for a small set of predictable reasons, and most of them are visible once you decode the token and compare its claims with what the server expects. This guide covers what is inside a token, how to read it and the mistakes behind most authentication failures.
What Is Inside a JWT
A JWT is three Base64URL encoded parts separated by dots: a header, a payload and a signature. The header names the signing algorithm and sometimes a key identifier. The payload carries claims, which are statements about the user and the token. The signature proves that the first two parts were produced by someone who holds the key and have not been changed.
The most important point is that the header and payload are encoded, not encrypted. Anyone who has the token can read them. Decoding therefore tells you what a token claims, but only a server that verifies the signature knows whether the claims can be trusted.
The Standard Claims to Check
- ▸iss (issuer): who created the token. The API must expect this exact value.
- ▸sub (subject): the user or client the token is about.
- ▸aud (audience): who the token is for. A token issued for one API is rejected by another, and a mismatched audience is one of the most common causes of 401 or 403.
- ▸exp (expiration time): when the token stops being valid, in seconds since 1970.
- ▸nbf (not before): the token is not valid until this time.
- ▸iat (issued at): when it was created.
- ▸jti (token ID): a unique identifier that lets a server track or revoke a token.
Why a Good Looking Token Is Rejected
- ▸Expired: compare exp with the current time. Decode the token and read the date, which is much faster than reading a ten digit number.
- ▸Seconds versus milliseconds: JWT time claims are in seconds. JavaScript's Date.now returns milliseconds. Setting exp to Date.now plus an hour produces a token that expires in the year 50000, and some libraries reject it as malformed.
- ▸Clock skew: if the server's clock is a minute ahead of the issuer's, a fresh token may look not yet valid or already expired. Most libraries accept a small leeway of a few minutes. Keep servers synchronized with network time.
- ▸Wrong audience or issuer: the token was issued by the staging identity provider and sent to the production API.
- ▸Signature mismatch: the verifying key differs from the signing key, a secret was rotated, or the key identifier points to a key the server no longer has. With JWKS endpoints, cache keys but refresh when an unknown key identifier appears.
- ▸Wrong algorithm: the server expects RS256 and the token uses HS256. Servers should pin the accepted algorithms and never accept the none algorithm.
- ▸Truncation and whitespace: an Authorization header cut at a length limit or with a stray newline breaks the signature.
Debugging Step by Step
Decode the token with the JWT Decoder and note the algorithm, issuer, audience, subject and the three time claims. Compare each against the API's configuration. If they all match, the problem is the signature or the key: check that the same secret or public key is used on both sides and that it is the current one. Finally look at the exact header you send, since proxies and clients sometimes add the Bearer prefix twice or drop it.
Security Habits That Prevent Future Problems
- ▸Never put secrets, passwords or sensitive personal data in the payload, because it is readable.
- ▸Keep access tokens short lived, from minutes to an hour, and use refresh tokens for longevity with proper rotation.
- ▸Store tokens where scripts cannot read them when possible. An HttpOnly cookie protects against theft by cross site scripting, while a token in local storage does not.
- ▸Always verify the signature, issuer, audience and expiry on the server. Decoding in the client is for display only.
- ▸Do not paste live production tokens into tools you do not trust. Use a tool that runs locally in your browser and rotate tokens you have exposed.
Conclusion
Most JWT failures are an expired or not yet valid token, a time claim in the wrong unit, a wrong issuer or audience, or a signature checked with the wrong key. Decode the token, compare each claim with what the server expects and keep clocks in sync. Decoding explains the failure, but trust always comes from signature verification on the server.
Free Tool
Open the JWT Decoder