From 8f3a2a8a4098693357b69d63a1dbec514ed7c701 Mon Sep 17 00:00:00 2001 From: Mark Adams Date: Mon, 17 Apr 2017 08:22:27 -0500 Subject: [PATCH 1/2] Stop rejecting tokens with future 'iat' values RFC 7519 does not specify or even suggest this type of validation on the 'iat' claim and it has caused issues for several consumers of PyJWT. This change removes the validation on future 'iat' values and leaves such things up to the application developer to implement. Fixes #190. --- CHANGELOG.md | 2 ++ docs/usage.rst | 3 --- jwt/api_jwt.py | 6 +----- tests/test_api_jwt.py | 7 ------- 4 files changed, 3 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 060876c8..d377d50d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). - Add support for ECDSA public keys in RFC 4253 (OpenSSH) format [#244][244] - Renamed commandline script `jwt` to `jwt-cli` to avoid issues with the script clobbering the `jwt` module in some circumstances. - Better error messages when using an algorithm that requires the cryptography package, but it isn't available [#230][230] +- Tokens with future 'iat' values are no longer rejected [#190][190] ### Fixed @@ -129,5 +130,6 @@ rarely used. Users affected by this should upgrade to 3.3+. [174]: https://github.com/jpadilla/pyjwt/pull/174 [182]: https://github.com/jpadilla/pyjwt/pull/182 [183]: https://github.com/jpadilla/pyjwt/pull/183 +[190]: https://github.com/jpadilla/pyjwt/pull/190 [213]: https://github.com/jpadilla/pyjwt/pull/214 [244]: https://github.com/jpadilla/pyjwt/pull/244 diff --git a/docs/usage.rst b/docs/usage.rst index c2e286c6..14a2bf7a 100644 --- a/docs/usage.rst +++ b/docs/usage.rst @@ -180,9 +180,6 @@ Issued At Claim (iat) This claim can be used to determine the age of the JWT. Its value MUST be a number containing a NumericDate value. Use of this claim is OPTIONAL. -If the `iat` claim is in the future, an `jwt.InvalidIssuedAtError` exception -will be raised. - .. code-block:: python jwt.encode({'iat': 1371720939}, 'secret') diff --git a/jwt/api_jwt.py b/jwt/api_jwt.py index 9703b8d6..059c4a04 100644 --- a/jwt/api_jwt.py +++ b/jwt/api_jwt.py @@ -121,14 +121,10 @@ def _validate_required_claims(self, payload, options): def _validate_iat(self, payload, now, leeway): try: - iat = int(payload['iat']) + int(payload['iat']) except ValueError: raise DecodeError('Issued At claim (iat) must be an integer.') - if iat > (now + leeway): - raise InvalidIssuedAtError('Issued At claim (iat) cannot be in' - ' the future.') - def _validate_nbf(self, payload, now, leeway): try: nbf = int(payload['nbf']) diff --git a/tests/test_api_jwt.py b/tests/test_api_jwt.py index 211f0dfd..bc9bda8e 100644 --- a/tests/test_api_jwt.py +++ b/tests/test_api_jwt.py @@ -154,13 +154,6 @@ def test_decode_raises_exception_if_nbf_is_not_int(self, jwt): with pytest.raises(DecodeError): jwt.decode(example_jwt, 'secret') - def test_decode_raises_exception_if_iat_in_the_future(self, jwt): - now = datetime.utcnow() - token = jwt.encode({'iat': now + timedelta(days=1)}, key='secret') - - with pytest.raises(InvalidIssuedAtError): - jwt.decode(token, 'secret') - def test_encode_datetime(self, jwt): secret = 'secret' current_datetime = datetime.utcnow() From 3447f0c0eb7de46042b5cda975d37e361168bf60 Mon Sep 17 00:00:00 2001 From: Mark Adams Date: Mon, 17 Apr 2017 08:25:39 -0500 Subject: [PATCH 2/2] Non-numeric 'iat' now raises InvalidIssuedAtError on decode() --- CHANGELOG.md | 2 ++ docs/usage.rst | 2 ++ jwt/api_jwt.py | 2 +- tests/test_api_jwt.py | 2 +- 4 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d377d50d..a84f2bf6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,8 @@ This project adheres to [Semantic Versioning](http://semver.org/). - Renamed commandline script `jwt` to `jwt-cli` to avoid issues with the script clobbering the `jwt` module in some circumstances. - Better error messages when using an algorithm that requires the cryptography package, but it isn't available [#230][230] - Tokens with future 'iat' values are no longer rejected [#190][190] +- Non-numeric 'iat' values now raise InvalidIssuedAtError instead of DecodeError + ### Fixed diff --git a/docs/usage.rst b/docs/usage.rst index 14a2bf7a..a485a94d 100644 --- a/docs/usage.rst +++ b/docs/usage.rst @@ -180,6 +180,8 @@ Issued At Claim (iat) This claim can be used to determine the age of the JWT. Its value MUST be a number containing a NumericDate value. Use of this claim is OPTIONAL. + If the `iat` claim is not a number, an `jwt.InvalidIssuedAtError` exception will be raised. + .. code-block:: python jwt.encode({'iat': 1371720939}, 'secret') diff --git a/jwt/api_jwt.py b/jwt/api_jwt.py index 059c4a04..bca68231 100644 --- a/jwt/api_jwt.py +++ b/jwt/api_jwt.py @@ -123,7 +123,7 @@ def _validate_iat(self, payload, now, leeway): try: int(payload['iat']) except ValueError: - raise DecodeError('Issued At claim (iat) must be an integer.') + raise InvalidIssuedAtError('Issued At claim (iat) must be an integer.') def _validate_nbf(self, payload, now, leeway): try: diff --git a/tests/test_api_jwt.py b/tests/test_api_jwt.py index bc9bda8e..61de6e05 100644 --- a/tests/test_api_jwt.py +++ b/tests/test_api_jwt.py @@ -142,7 +142,7 @@ def test_decode_raises_exception_if_iat_is_not_int(self, jwt): 'eyJpYXQiOiJub3QtYW4taW50In0.' 'H1GmcQgSySa5LOKYbzGm--b1OmRbHFkyk8pq811FzZM') - with pytest.raises(DecodeError): + with pytest.raises(InvalidIssuedAtError): jwt.decode(example_jwt, 'secret') def test_decode_raises_exception_if_nbf_is_not_int(self, jwt):