Skip to content
ecdsa.com
jose (JavaScript)JWT libraries

Error message

"nbf" claim timestamp check failed

jose (JavaScript) — JWTClaimValidationFailed, code ERR_JWT_CLAIM_VALIDATION_FAILED

What it means

The token carries an `nbf` ("not before") claim that is still in the future according to the verifier's clock, so jose refuses it as not yet valid. The signature and the other claims may be perfectly fine; the error is about time only. It almost always means the issuer's and the verifier's clocks disagree by more than the tolerance you allow (zero by default).

Why it happens

How to fix it

  1. 1.

    Allow a small, explicit clock skew

    `clockTolerance` accepts seconds or a duration string. 30–60 seconds absorbs real-world drift; it is not a way to accept tokens minutes early.

    js
    import { jwtVerify } from "jose";
    
    const { payload } = await jwtVerify(token, jwks, {
      algorithms: ["ES256"],
      clockTolerance: "30s", // applies to nbf, exp and iat
    });
  2. 2.

    Print the timeline before changing configuration

    Compare `nbf` with the verifier's current time. A difference of seconds points at skew; hours at a time-zone or unit bug in the issuer; a 13-digit `nbf` at milliseconds.

    js
    import { decodeJwt } from "jose";
    
    const { iat, nbf, exp } = decodeJwt(token);
    const now = Math.floor(Date.now() / 1000);
    console.log({ iat, nbf, exp, now, nbfInSeconds: nbf - now });
  3. 3.

    Fix the clock that drifts

    Run NTP (chrony or systemd-timesyncd) on every host that issues or verifies tokens. Tolerance hides small skew; it should not have to hide large skew.

    bash
    timedatectl status          # "System clock synchronized: yes"
    chronyc tracking            # offset from the NTP reference
    date -u +%s                 # compare with the token's nbf

Related errors

Browse the full signature error database