Separate the claim from the validation window
Use a synthetic token for investigation. Read exp with JWT Decoder, then convert its seconds value with Unix Timestamp Converter. Check the server’s UTC clock as well as the browser’s time.
For a token whose exp maps to 12:00:00 UTC, a five-minute tolerance can allow lifetime validation shortly after noon. This example describes lifetime tolerance alone: signature, issuer, audience, algorithm and application policy must still succeed.
| Server UTC | exp | Interpretation with a five-minute tolerance |
|---|---|---|
| 11:59:00 | 12:00:00 | Before expiry |
| 12:02:00 | 12:00:00 | Within the configured tolerance |
| 12:06:00 | 12:00:00 | Beyond the tolerance; lifetime should fail |
Inspect the actual authentication scheme
The following fragment targets ASP.NET Core JwtBearer options backed by Microsoft.IdentityModel.Tokens.TokenValidationParameters. It is a configuration example, not a complete authentication setup. Keep your existing signing-key, issuer and audience configuration.
If the business requirement needs zero tolerance, explicitly set ClockSkew to TimeSpan.Zero and keep ValidateLifetime enabled. First confirm synchronized clocks and test the consequences for clients. Do not disable lifetime validation to make an expired token appear to work.
// Inside the AddJwtBearer options callback:
options.TokenValidationParameters.ValidateLifetime = true;
options.TokenValidationParameters.ClockSkew = TimeSpan.Zero;
// Retain the configured signing keys, issuer and audience validation.Test the validation path rather than just the decoder
Check which authentication scheme protects the endpoint. A cookie session, cached authorization result, refresh flow, custom lifetime validator or unprotected route can make a request succeed for reasons unrelated to this token’s exp. Confirm which token was actually sent without logging its full value.
In an integration test using a dedicated test signing key, issue tokens expiring clearly before, inside and beyond the chosen tolerance. Freeze or control time where the framework permits. Assert the protected endpoint’s status and authentication outcome, not merely the decoded JSON.
A local integration check for this guide used .NET 10, Microsoft.AspNetCore.Authentication.JwtBearer 10.0.12 and Microsoft.IdentityModel.Tokens 8.19.2. A protected endpoint accepted a test token expired by two minutes with default skew, rejected the same expiry with zero skew, rejected a token expired by six minutes with default skew, and accepted a future-expiring token with zero skew.
Those results verify the stated lifetime behavior for that test configuration, not your deployed authentication pipeline. Record your own installed versions and protected-endpoint outcomes. Your server remains responsible for cryptographic verification and authorization.
| Expiry relative to request | ClockSkew | Protected endpoint |
|---|---|---|
| −2 minutes | Default 5 minutes | HTTP 200 |
| −2 minutes | Zero | HTTP 401 |
| −6 minutes | Default 5 minutes | HTTP 401 |
| +2 minutes | Zero | HTTP 200 |
References
Use the linked specifications and product documentation to check behavior in your own environment.
Continue troubleshooting
Related tools
Frequently asked questions
Does a decoded exp prove server rejection?
No. The server applies its configured validation policy to the actual request.
Should I disable lifetime validation?
No. Keep lifetime validation enabled and choose an intentional clock-tolerance policy.
Can PageUtil verify my signing key?
No. PageUtil reads token segments locally and does not verify their signature.