{"record":{"id":"694d5415a96490d5","repo":"jwtk/jjwt","slug":"jwt-early-by-differencemillis-milliseconds-befor","errorCode":null,"errorMessage":"JWT early by <differenceMillis> milliseconds before <nbfVal>. Current time: <nowVal>. Allowed clock skew: <allowedClockSkewMillis> milliseconds.","messagePattern":"JWT early by <differenceMillis> milliseconds before <nbfVal>\\. Current time: <nowVal>\\. Allowed clock skew: <allowedClockSkewMillis> milliseconds\\.","errorType":"exception","errorClass":"PrematureJwtException","httpStatus":null,"severity":"error","filePath":"impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java","lineNumber":709,"sourceCode":"            }\n\n            // https://www.rfc-editor.org/rfc/rfc7519.html#section-4.1.5\n            // token MUST NOT be accepted before any specified nbf time:\n            Date nbf = claims.getNotBefore();\n            if (nbf != null) {\n\n                long minTime = nowTime + this.allowedClockSkewMillis;\n                Date min = allowSkew ? new Date(minTime) : now;\n                if (min.before(nbf)) {\n                    String nbfVal = DateFormats.formatIso8601(nbf, true);\n                    String nowVal = DateFormats.formatIso8601(now, true);\n\n                    long differenceMillis = nbf.getTime() - nowTime;\n\n                    String msg = \"JWT early by \" + differenceMillis + \" milliseconds before \" + nbfVal +\n                            \". Current time: \" + nowVal + \". Allowed clock skew: \" +\n                            this.allowedClockSkewMillis + \" milliseconds.\";\n                    throw new PrematureJwtException(header, claims, msg);\n                }\n            }\n\n            validateExpectedClaims(header, claims);\n        }\n\n        return jwt;\n    }\n\n    /**\n     * @since 0.10.0\n     */\n    private static Object normalize(Object o) {\n        if (o instanceof Integer) {\n            o = ((Integer) o).longValue();\n        }\n        return o;\n    }","sourceCodeStart":691,"sourceCodeEnd":727,"githubUrl":"https://github.com/jwtk/jjwt/blob/fb71496164c71442d08adec4571d9616ed5e1b8d/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java#L691-L727","documentation":"Thrown as PrematureJwtException during JWT parsing when the token's 'nbf' (not-before) claim is later than the current time, even after allowing the configured clock skew (default 0 unless setClockSkewSeconds was called). JJWT treats an nbf in the future as 'this token is not valid yet' and refuses to parse it. The message quantifies how many milliseconds early the token is.","triggerScenarios":"Calling jwtParser.parse(...) / parseSignedClaims(...) / parseSignedContent(...) on a JWT whose 'nbf' claim timestamp is after the system clock of the machine doing the parsing, and the difference exceeds allowedClockSkewMillis.","commonSituations":"Clock drift between the token issuer's server and the verifier; issuing tokens with an nbf set slightly in the future by mistake; tokens minted on a machine with a fast clock and validated on one with a slow clock; container/KVM environments where clocks aren't synchronized (no NTP).","solutions":["Synchronize clocks on the issuing and verifying hosts (NTP/chrony).","Increase allowed clock skew: parserBuilder.setClockSkewSeconds(...) to cover the drift window.","Regenerate the token with an nbf <= now (or omit nbf) if the issuer set it incorrectly.","If tests intentionally use future nbf, set the parser's Clock to a fixed date at or after nbf via parserBuilder.setClock(Clock.fixed(...))."],"exampleFix":"// before\nJwts.parser().verifyWith(key).build().parseSignedClaims(jwt); // PrematureJwtException\n// after\nClaims claims = Jwts.parser()\n    .clockSkewSeconds(300) // tolerate up to 5 min of clock drift\n    .verifyWith(key)\n    .build()\n    .parseSignedClaims(jwt).getPayload();","handlingStrategy":"try-catch","validationCode":"// decode payload without verification and inspect nbf\nString[] parts = jwt.split(\"\\\\.\");\nString payload = new String(java.util.Base64.getUrlDecoder().decode(parts[1]));\nlong nbf = com.fasterxml.jackson.databind.json.JsonMapper.builder().build()\n    .readTree(payload).path(\"nbf\").asLong(0);\nif (nbf > System.currentTimeMillis() + 300_000) {\n    throw new IllegalStateException(\"Token not valid yet (nbf too far in future)\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    claims = Jwts.parser().clockSkewSeconds(300).verifyWith(key).build().parseSignedClaims(jwt).getPayload();\n} catch (io.jsonwebtoken.PrematureJwtException e) {\n    // token not yet valid; retry after e's indicated delay or reject\n}","preventionTips":["Run NTP/chrony on all hosts that issue or verify tokens","Configure a reasonable clockSkewSeconds (e.g. 30-300) on every parser","Avoid setting nbf in the future unless intentionally delaying validity","In tests, use setClock(Clock.fixed(...)) instead of fabricating future nbf values"],"tags":["jwt","clock-skew","token-validation","timing"],"backgroundTag":"jwt-token-expired","analyzedSha":"fb71496164c71442d08adec4571d9616ed5e1b8d","analyzedAt":"2026-09-09T00:33:09.982Z","contentChangedAt":"2026-09-09T00:33:09.982Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}