Skip to content

Commit 181dc51

Browse files
committed
Report out-of-range NumericDate claims distinctly from non-numeric ones
exp, nbf and iat are NumericDate claims, which per RFC 7519 are JSON numbers and may be written in scientific notation. getInstantFromSeconds gated on canConvertToLong() and threw "contained a non-numeric date value" when it was false. For a numeric value that overflows a long (for example 1.733162101e+26 from issue #706) that message is wrong: the value is numeric, just not representable as a NumericDate. Split the two failure modes so a genuinely non-numeric value keeps the existing message, while a numeric value that does not fit a long throws a message naming the value and the real reason. In-range scientific values such as 1.7e9 continue to decode to the correct instant. Fixes #706 Signed-off-by: Arpit Jain <arpitjain099@gmail.com>
1 parent 695fd2b commit 181dc51

2 files changed

Lines changed: 39 additions & 1 deletion

File tree

lib/src/main/java/com/auth0/jwt/impl/PayloadDeserializer.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,10 +74,20 @@ Instant getInstantFromSeconds(Map<String, JsonNode> tree, String claimName) {
7474
if (node == null || node.isNull()) {
7575
return null;
7676
}
77-
if (!node.canConvertToLong()) {
77+
// A NumericDate per RFC 7519 is a JSON number and may be written in scientific notation
78+
// (for example 1.7e9). Split the two failure modes so the thrown error is accurate: a
79+
// genuinely non-numeric value, versus a numeric value that is out of the range a long can
80+
// hold (such as 1.733162101e+26). Previously both produced "non-numeric date value", which
81+
// is wrong for the second case and made large/scientific values look unsupported.
82+
if (!node.isNumber()) {
7883
throw new JWTDecodeException(
7984
String.format("The claim '%s' contained a non-numeric date value.", claimName));
8085
}
86+
if (!node.canConvertToLong()) {
87+
throw new JWTDecodeException(String.format(
88+
"The claim '%s' value (%s) is out of the range representable as a NumericDate.",
89+
claimName, node.asText()));
90+
}
8191
return Instant.ofEpochSecond(node.asLong());
8292
}
8393

lib/src/test/java/com/auth0/jwt/impl/PayloadDeserializerTest.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,34 @@ public void shouldGetLargeInstantWhenParsingNumericNode() {
241241
assertThat(instant.toEpochMilli(), is(2147493647L * 1000));
242242
}
243243

244+
// https://github.com/auth0/java-jwt/issues/706 - a NumericDate may be written in scientific
245+
// notation. An in-range value must still resolve to the right instant.
246+
@Test
247+
public void shouldGetInstantWhenParsingScientificNotationNode() {
248+
Map<String, JsonNode> tree = new HashMap<>();
249+
DoubleNode node = new DoubleNode(1.7e9);
250+
tree.put("key", node);
251+
252+
Instant instant = deserializer.getInstantFromSeconds(tree, "key");
253+
assertThat(instant, is(notNullValue()));
254+
assertThat(instant, is(Instant.ofEpochSecond(1_700_000_000L)));
255+
}
256+
257+
// A numeric value that does not fit a long (the exact value reported in issue #706) must be
258+
// rejected as out of range, not mislabeled as non-numeric.
259+
@Test
260+
public void shouldThrowOutOfRangeWhenNumericDateExceedsLong() {
261+
exception.expect(JWTDecodeException.class);
262+
exception.expectMessage(
263+
"The claim 'key' value (1.733162101E26) is out of the range representable as a NumericDate.");
264+
265+
Map<String, JsonNode> tree = new HashMap<>();
266+
DoubleNode node = new DoubleNode(1.733162101e+26);
267+
tree.put("key", node);
268+
269+
deserializer.getInstantFromSeconds(tree, "key");
270+
}
271+
244272
@Test
245273
public void shouldGetNullStringWhenParsingNullNode() {
246274
Map<String, JsonNode> tree = new HashMap<>();

0 commit comments

Comments
 (0)