jwtk/jjwt · error · PrematureJwtException
JWT early by <differenceMillis> milliseconds before <nbfVal>
Error message
JWT early by <differenceMillis> milliseconds before <nbfVal>. Current time: <nowVal>. Allowed clock skew: <allowedClockSkewMillis> milliseconds.
What it means
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.
Source
Thrown at impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java:709
}
// https://www.rfc-editor.org/rfc/rfc7519.html#section-4.1.5
// token MUST NOT be accepted before any specified nbf time:
Date nbf = claims.getNotBefore();
if (nbf != null) {
long minTime = nowTime + this.allowedClockSkewMillis;
Date min = allowSkew ? new Date(minTime) : now;
if (min.before(nbf)) {
String nbfVal = DateFormats.formatIso8601(nbf, true);
String nowVal = DateFormats.formatIso8601(now, true);
long differenceMillis = nbf.getTime() - nowTime;
String msg = "JWT early by " + differenceMillis + " milliseconds before " + nbfVal +
". Current time: " + nowVal + ". Allowed clock skew: " +
this.allowedClockSkewMillis + " milliseconds.";
throw new PrematureJwtException(header, claims, msg);
}
}
validateExpectedClaims(header, claims);
}
return jwt;
}
/**
* @since 0.10.0
*/
private static Object normalize(Object o) {
if (o instanceof Integer) {
o = ((Integer) o).longValue();
}
return o;
}View on GitHub (pinned to fb71496164)
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(...)).
Example fix
// before
Jwts.parser().verifyWith(key).build().parseSignedClaims(jwt); // PrematureJwtException
// after
Claims claims = Jwts.parser()
.clockSkewSeconds(300) // tolerate up to 5 min of clock drift
.verifyWith(key)
.build()
.parseSignedClaims(jwt).getPayload(); Defensive patterns
Strategy: try-catch
Validate before calling
// decode payload without verification and inspect nbf
String[] parts = jwt.split("\\.");
String payload = new String(java.util.Base64.getUrlDecoder().decode(parts[1]));
long nbf = com.fasterxml.jackson.databind.json.JsonMapper.builder().build()
.readTree(payload).path("nbf").asLong(0);
if (nbf > System.currentTimeMillis() + 300_000) {
throw new IllegalStateException("Token not valid yet (nbf too far in future)");
} Try / catch
try {
claims = Jwts.parser().clockSkewSeconds(300).verifyWith(key).build().parseSignedClaims(jwt).getPayload();
} catch (io.jsonwebtoken.PrematureJwtException e) {
// token not yet valid; retry after e's indicated delay or reject
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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).
Related errors
- JWT expired <differenceMillis> milliseconds ago at <expVal>.
- Unexpected unsecured Claims JWT.
- Unexpected content JWS.
- Unexpected Claims JWS.
- Unexpected content JWE.
AI-assisted analysis of jwtk/jjwt@fb71496164 (2026-09-09).
Data as JSON: /api/errors/694d5415a96490d5.
Report an issue: GitHub.