Skip to content

Report out-of-range NumericDate claims distinctly from non-numeric ones#774

Open
arpitjain099 wants to merge 1 commit into
auth0:masterfrom
arpitjain099:fix/exp-scientific-notation-706
Open

Report out-of-range NumericDate claims distinctly from non-numeric ones#774
arpitjain099 wants to merge 1 commit into
auth0:masterfrom
arpitjain099:fix/exp-scientific-notation-706

Conversation

@arpitjain099
Copy link
Copy Markdown

Fixes #706

What is actually happening

While looking into this I found that in-range scientific notation already decodes correctly. A claim like {"exp": 1.7e9} is parsed by Jackson as a DoubleNode whose canConvertToLong() is true, and getInstantFromSeconds already handles it and returns Instant.ofEpochSecond(1_700_000_000).

The value in the report, 1.733162101e+26, is different: it is about 1.7e26 seconds (a year around 5.5e18), which overflows long and is not representable as a NumericDate or an Instant. So it genuinely cannot be decoded to a date. The defect is that PayloadDeserializer.getInstantFromSeconds reported it as The claim 'exp' contained a non-numeric date value, which is misleading: the value is numeric, it is just out of range.

Fix

Split the two failure modes in getInstantFromSeconds:

  • not a number: keep the existing non-numeric date value message.
  • numeric but overflows long: a new, accurate message, The claim '<name>' value (<value>) is out of the range representable as a NumericDate.

In-range scientific-notation values continue to decode unchanged. Clamping an absurd overflow value to some wrong year would be worse than a clear rejection, so the out-of-range case is rejected with the precise error.

Tests

Added to PayloadDeserializerTest:

  • shouldGetInstantWhenParsingScientificNotationNode: 1.7e9 decodes to Instant.ofEpochSecond(1_700_000_000) (documents that in-range scientific notation works).
  • shouldThrowOutOfRangeWhenNumericDateExceedsLong: 1.733162101e+26 raises the new out-of-range message.

The existing non-numeric and normal-integer tests still pass. The directly affected suites (PayloadDeserializerTest, JsonNodeClaimTest, PayloadImplTest, JWTVerifierTest, JWTDecoderTest) run green. I ran these on JDK 11 because the repo's Gradle wrapper (6.9.2) rejects newer JDKs; CI will exercise the full version matrix.

Scope

This is narrower than the title might suggest: scientific notation is already supported for representable values, so this PR fixes the misleading error for out-of-range values and adds the missing test coverage rather than adding a new feature. A separate pre-existing edge (a plain integer that passes canConvertToLong() but still overflows Instant.ofEpochSecond) is orthogonal to this issue and not addressed here.

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 auth0#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 auth0#706

Signed-off-by: Arpit Jain <arpitjain099@gmail.com>
@arpitjain099 arpitjain099 requested a review from a team as a code owner June 5, 2026 11:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

exp claim doesnt support scientific notation

1 participant