From 839350f92c4c4637a5fff72a42f880789b42a743 Mon Sep 17 00:00:00 2001 From: Eryx-Z Date: Sat, 17 Oct 2026 06:12:16 +0800 Subject: [PATCH] Raise JWTClaimsError for non-numeric exp/iat/nbf claims int() on Infinity or structured JSON values raises OverflowError or TypeError, which escaped jose.jwt.decode() even though the documented contract is JWTClaimsError. Catch those alongside ValueError. Closes #420 --- jose/jwt.py | 6 +++--- tests/test_jwt.py | 18 +++++++++++++++++- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/jose/jwt.py b/jose/jwt.py index f47e4dd..c6e6dd1 100644 --- a/jose/jwt.py +++ b/jose/jwt.py @@ -267,7 +267,7 @@ def _validate_iat(claims): try: int(claims["iat"]) - except ValueError: + except (ValueError, TypeError, OverflowError): raise JWTClaimsError("Issued At claim (iat) must be an integer.") @@ -292,7 +292,7 @@ def _validate_nbf(claims, leeway=0): try: nbf = int(claims["nbf"]) - except ValueError: + except (ValueError, TypeError, OverflowError): raise JWTClaimsError("Not Before claim (nbf) must be an integer.") now = timegm(datetime.now(UTC).utctimetuple()) @@ -322,7 +322,7 @@ def _validate_exp(claims, leeway=0): try: exp = int(claims["exp"]) - except ValueError: + except (ValueError, TypeError, OverflowError): raise JWTClaimsError("Expiration Time claim (exp) must be an integer.") now = timegm(datetime.now(UTC).utctimetuple()) diff --git a/tests/test_jwt.py b/tests/test_jwt.py index f9d54cd..c9d8f2f 100644 --- a/tests/test_jwt.py +++ b/tests/test_jwt.py @@ -12,7 +12,7 @@ import pytest from jose import jws, jwt -from jose.exceptions import JWTError +from jose.exceptions import JWTClaimsError, JWTError @pytest.fixture @@ -531,3 +531,19 @@ def test_require(self, claims, key, claim, value): new_claims[claim] = value token = jwt.encode(new_claims, key) jwt.decode(token, key, options=options, audience=str(value)) + + +class TestTimeClaimTypeErrors: + """Non-numeric time claims must raise JWTClaimsError (#420).""" + + @pytest.mark.parametrize("claim", ["exp", "iat", "nbf"]) + @pytest.mark.parametrize( + "bad", + [float("inf"), float("-inf"), 1e999, [1, 2], {"x": 1}], + ) + def test_non_integer_time_claim_raises_jwt_claims_error(self, claim, bad): + from jose.jwt import _validate_exp, _validate_iat, _validate_nbf + + validators = {"exp": _validate_exp, "iat": _validate_iat, "nbf": _validate_nbf} + with pytest.raises(JWTClaimsError): + validators[claim]({claim: bad})