Developer tools · JWT decoder
JWT exp, iat and nbf: NumericDate Is Seconds, Not Milliseconds
· How it works
jwt timestamps debugging
JavaScript gives you milliseconds and JWT wants seconds, so timestamps go wrong by a factor of a thousand. This post explains NumericDate and how to read the three time claims correctly.
Tokens that never expire or expire before they arrive — the two symptoms of a units mistake
A factor-of-one-thousand mistake produces dramatic symptoms. Supplying JavaScript milliseconds where a token producer expects epoch seconds can push an expiry thousands of years away. Dividing a seconds value again can place it near 1970, making a newly issued token appear expired before its first legitimate request.
A decoder helps expose scale by showing the numeric claim beside an ISO reading. That display is diagnostic only. An attacker can write any `exp`, `iat` or `nbf` number into an unsigned or forged payload, so the converted clock time has authority only after signature and policy validation elsewhere.
NumericDate in RFC 7519 — seconds since the Unix epoch, as a JSON number, with fractions allowed but rarely used
JWT time claims use a NumericDate representation: a JSON number counting seconds from the Unix epoch. Fractional numbers can represent subsecond positions because the implementation multiplies the value by 1,000 before constructing a Date. It does not round a valid finite number to an integer first.
ToolAcre recognises `exp`, `nbf`, `iat`, `auth_time` and `updated_at` as time-shaped fields for display. Only the first three are among its registered-claim descriptions. Non-numeric, infinite or invalid Date results are omitted rather than rendered as meaningful times, preventing a string such as “soon” from masquerading as a timestamp.
Date.now() is milliseconds — the JavaScript habit that produces far-future expiries
`Date.now()` returns milliseconds, while a NumericDate value is expressed in seconds. A producer deriving a claim from the browser clock therefore needs an explicit scale conversion, commonly dividing by 1,000 before applying its own rounding policy. The ToolAcre read path performs the inverse multiplication solely for display.
Keep the unit conversion visible in code review. A thirteen-digit value in `exp` is a useful warning sign, but digit counting is not verification and cannot replace the producer’s contract. The decoder will attempt to render any finite numeric claim that JavaScript Date can represent; it does not silently reinterpret milliseconds as seconds.
exp, nbf and iat — expires, not-before and issued-at, and how a verifier applies each
`exp` names the time after which a verifier should no longer accept a token under its policy. `nbf` names a boundary before which it should not be accepted. `iat` records an issuance time. ToolAcre labels these meanings and compares only `exp` and `nbf` with the supplied reference clock.
The returned state is `expired` when the decoded expiry is earlier than now, `future` when not-before lies later than now, and `past` for the other displayed time claims. These labels are observations about payload arithmetic. They are not an authentication decision and do not evaluate issuer, audience, key or signature.
Clock differences and leeway belong to the verifier; this decoder defines neither
The outline asked how much clock skew is reasonable, but neither the JWT decoder configuration nor implementation defines a leeway. That number belongs to the verifier and its deployment requirements. Inventing a default here would turn an inspection article into undocumented security policy, so this section intentionally provides none.
If a service rejects a token near a boundary, compare the service clock, issuer clock and configured verifier policy using trusted logs. ToolAcre resolves claims against the browser’s current Date with no tolerance window. Its result may therefore differ from a server that deliberately applies leeway, even when both parse the same number.
Worked example — converting a sample exp value to a human-readable time and checking it against iat
Suppose a synthetic payload contains `iat: 1717243200` and `exp: 1717246800`. Multiplying by 1,000 gives ISO instants `2024-06-01T12:00:00.000Z` and `2024-06-01T13:00:00.000Z`. Subtracting the raw seconds values yields a one-hour interval without mixing browser milliseconds into the calculation.
That arithmetic describes what the payload says. It does not show that the issuer chose those values or that one hour is suitable for any application. ToolAcre pretty-prints the numbers, generates UTC rows and may call the expiry old relative to today; a verifier must independently authenticate and enforce its own acceptance rules.
What this does not cover — whether a specific server will accept the token, which depends on its clock and leeway; a decoder shows the values, not the verdict
A decoder cannot predict whether a specific server will accept the token. The server may use a different clock, a configured tolerance, a stricter claim schema or additional issuer and audience checks. Signature failure alone can reject a token whose displayed NumericDates look perfectly ordinary.
Conversely, a future-looking expiry does not make an unverified token valid. Treat the time table as a way to spot likely unit errors and gather evidence for debugging. The actual verdict belongs in server logs or a controlled verification test with the expected key and policy, never in the decode panel.
Takeaway: read the claims, do the arithmetic — the ToolAcre JWT decoder shows exp, iat and nbf so you can check the units yourself
Read the claims and perform scale arithmetic deliberately: NumericDate seconds become JavaScript milliseconds only at the Date boundary. ToolAcre makes that multiplication explicit in source and displays the resulting ISO value, while ignoring malformed time types instead of guessing what their authors intended.
Keep the security distinction equally explicit. An `exp` display is not expiry enforcement, `nbf` display is not admission control, and `iat` is not proof of issuance. After inspecting a throwaway token, use the trusted verifier to authenticate it and apply the service’s real clock and claim policy.