How do a JWT's exp, nbf and iat claims differ, and how are their values represented?
answer
- Two edges and a stamp
- Counted in seconds, not milliseconds
- UTC only, no offset field
- Clocks drift, so a little leeway
- Age is a different question from expiry
basics
~20 sexp is the instant from which a token must not be accepted, nbf the instant before which it must not be accepted, and iat when it was minted. All three are NumericDate values: seconds — not milliseconds — since the Unix epoch in UTC.
solid answer
~40 sThe three time claims bound a token's life. **`nbf`** opens the window: before that instant the token must be rejected. **`exp`** closes it: on or at any time after that instant the token must be rejected. **`iat`** is not a boundary at all — it records the minting time, which lets a verifier judge the token's *age* independently of the window. All three are **NumericDate** values: a JSON number counting seconds since 1970-01-01T00:00:00Z, UTC, ignoring leap seconds. That unit is the classic bug: platforms whose clock APIs return milliseconds produce values a thousand times too large, so an `exp` lands millennia away and a `nbf` rejects every token. Because independent machines never agree exactly, verifiers usually permit a small leeway — typically a minute or two — when comparing against `exp` and `nbf`.
code
json · 5 lines{
"iat": 1767225600,
"nbf": 1767225600,
"exp": 1767229200
}go deeper
Know that exp ends validity, nbf begins it, iat records issuance, and that all three are epoch seconds in UTC rather than formatted dates.
Explain NumericDate precisely, describe the milliseconds bug and its two very different symptoms, and say why verifiers allow a small leeway.
Diagnose boundary-clustered rejections as clock drift, insist on time synchronization rather than wider tolerance, and use iat for age policies such as step-up and bulk invalidation.
Own lifetime policy across the platform: how short tokens can be before leeway dominates, how credential changes invalidate outstanding tokens, and what the fleet's clock guarantees actually are.
## The validity window Think of `nbf` and `exp` as the two edges of an interval and `iat` as a stamp inside it. - **`nbf` (not before)** — the token must not be accepted *before* this time. Its everyday value is deferred activation: a credential minted now but valid from a later moment. - **`exp` (expiration time)** — the token must not be accepted *on or after* this time. This is the only lifetime control the format itself provides. - **`iat` (issued at)** — when the token was minted. It bounds nothing by itself; it enables age-based reasoning. Most tokens carry `exp` and `iat` and omit `nbf`, because immediate validity is the normal case. ## NumericDate — seconds, UTC All three are NumericDate: a JSON number of seconds since the Unix epoch, in UTC, ignoring leap seconds. Three consequences worth stating explicitly: 1. **Seconds, not milliseconds.** A runtime whose clock returns milliseconds will emit values roughly a thousand times too big unless you divide. The symptom depends on the claim: an inflated `exp` yields a token that effectively never expires — a security hole that no test catches, because everything works; an inflated `nbf` yields a token nothing ever accepts — a loud, easy bug. The dangerous one is silent. 2. **UTC, no time zone.** There is no offset field and no local-time interpretation. Formatting a local timestamp into a claim shifts the window by the offset. 3. **A number, not a string.** `"exp": "1767229200"` is not a NumericDate, and strict verifiers reject it. ## Clock skew The issuer and the verifier are different machines with independently drifting clocks. A token minted "now" can look as if it lies in the future to a verifier whose clock runs slightly behind, and a token about to expire can look expired to one running ahead. Without tolerance you get sporadic, unreproducible rejections concentrated at the boundaries — the classic "one instance in the pool rejects tokens" incident. Verifiers therefore commonly allow a small leeway when comparing against `exp` and `nbf`: the token is accepted if it is within that many seconds of the boundary. The guidance is that this should be *small* — a matter of a couple of minutes at most — because leeway extends the life of an expired credential by exactly that amount. Two engineering points follow. First, leeway is a patch over clock drift, not a substitute for time synchronization; a fleet without NTP will eventually drift past any tolerance you configure. Second, leeway interacts badly with very short token lifetimes: five minutes of tolerance on a sixty-second token means the token is honoured for six times its nominal life. ## Age policies with iat `iat` supports rules `exp` cannot express: - **Step-up authentication.** A sensitive operation may require a token minted within the last few minutes, forcing a fresh authentication regardless of remaining lifetime. - **Bulk invalidation.** Storing a per-user "credentials changed at" timestamp and rejecting tokens whose `iat` predates it invalidates every outstanding token for that user after a password reset — one small piece of state instead of a list of tokens. Both compare `iat` against the verifier's clock, so both inherit the same skew concerns; a token appearing to be issued in the future is a sign of drift, not of malice, and deserves the same small tolerance. ## What a strong answer contains Distinguish the three claims precisely, including that `exp` is exclusive of acceptance *on* the boundary; name NumericDate and its unit; and explain skew as a distributed-systems fact with a deliberately small tolerance, not as a knob to turn up when tokens are rejected.
- What actually goes wrong when exp is written in milliseconds?The value lands thousands of years in the future, so the token effectively never expires. Nothing fails, no test breaks, and a leaked token stays usable indefinitely — which makes it far more dangerous than the milliseconds-in-nbf version, where every token is rejected immediately and someone fixes it within the hour.
- How much clock skew leeway is reasonable, and what does increasing it cost?A small tolerance — on the order of a minute — is normal. Every second of leeway is a second an expired token remains usable, and the tolerance becomes proportionally worse as token lifetimes shrink. Treat repeated boundary rejections as a clock-synchronization problem to fix, not a tolerance to raise.
- When is nbf genuinely useful?When a credential is minted ahead of the moment it should take effect — a token issued as part of a scheduled activation, or one deliberately delayed so a preceding step must complete first. Because immediate validity is the normal case, most issuers omit nbf entirely rather than set it equal to iat.
saying these in an interview costs you the question
- Says NumericDate values are milliseconds
- Thinks exp is an ISO-8601 string
- Treats iat as the expiry or as a duration
- Raises skew tolerance instead of fixing clocks
- Assumes local time zone applies to the values