diff --git a/jose/jwt.py b/jose/jwt.py index b364b4ba..8972711f 100644 --- a/jose/jwt.py +++ b/jose/jwt.py @@ -11,7 +11,7 @@ from .constants import ALGORITHMS from .exceptions import ExpiredSignatureError, JWSError, JWTClaimsError, JWTError -from .utils import calculate_at_hash, timedelta_total_seconds +from .utils import calculate_at_hash, timedelta_total_seconds, utcnow def encode(claims, key, algorithm=ALGORITHMS.HS256, headers=None, access_token=None): @@ -281,7 +281,7 @@ def _validate_nbf(claims, leeway=0): except ValueError: raise JWTClaimsError("Not Before claim (nbf) must be an integer.") - now = timegm(datetime.utcnow().utctimetuple()) + now = timegm(utcnow().utctimetuple()) if nbf > (now + leeway): raise JWTClaimsError("The token is not yet valid (nbf)") @@ -311,7 +311,7 @@ def _validate_exp(claims, leeway=0): except ValueError: raise JWTClaimsError("Expiration Time claim (exp) must be an integer.") - now = timegm(datetime.utcnow().utctimetuple()) + now = timegm(utcnow().utctimetuple()) if exp < (now - leeway): raise ExpiredSignatureError("Signature has expired.") diff --git a/jose/utils.py b/jose/utils.py index d04c4ac0..03f96f6b 100644 --- a/jose/utils.py +++ b/jose/utils.py @@ -1,5 +1,6 @@ import base64 import struct +from datetime import datetime, timezone # Piggyback of the backends implementation of the function that converts a long # to a bytes stream. Some plumbing is necessary to have the signatures match. @@ -105,3 +106,8 @@ def ensure_binary(s): if isinstance(s, str): return s.encode("utf-8", "strict") raise TypeError(f"not expecting type '{type(s)}'") + + +def utcnow(): + # datetime.utcnow() is deprecated since Python 3.12 + return datetime.now(timezone.utc) diff --git a/tests/test_jwt.py b/tests/test_jwt.py index 8c2e262f..9c010cbe 100644 --- a/tests/test_jwt.py +++ b/tests/test_jwt.py @@ -6,6 +6,7 @@ from jose import jws, jwt from jose.exceptions import JWTError +from jose.utils import utcnow @pytest.fixture @@ -180,7 +181,7 @@ def test_leeway_is_int(self): pass def test_leeway_is_timedelta(self, claims, key): - nbf = datetime.utcnow() + timedelta(seconds=5) + nbf = utcnow() + timedelta(seconds=5) leeway = timedelta(seconds=10) claims = { @@ -209,7 +210,7 @@ def test_nbf_not_int(self, key): jwt.decode(token, key) def test_nbf_datetime(self, key): - nbf = datetime.utcnow() - timedelta(seconds=5) + nbf = utcnow() - timedelta(seconds=5) claims = {"nbf": nbf} @@ -217,7 +218,7 @@ def test_nbf_datetime(self, key): jwt.decode(token, key) def test_nbf_with_leeway(self, key): - nbf = datetime.utcnow() + timedelta(seconds=5) + nbf = utcnow() + timedelta(seconds=5) claims = { "nbf": nbf, @@ -229,7 +230,7 @@ def test_nbf_with_leeway(self, key): jwt.decode(token, key, options=options) def test_nbf_in_future(self, key): - nbf = datetime.utcnow() + timedelta(seconds=5) + nbf = utcnow() + timedelta(seconds=5) claims = {"nbf": nbf} @@ -239,7 +240,7 @@ def test_nbf_in_future(self, key): jwt.decode(token, key) def test_nbf_skip(self, key): - nbf = datetime.utcnow() + timedelta(seconds=5) + nbf = utcnow() + timedelta(seconds=5) claims = {"nbf": nbf} @@ -261,7 +262,7 @@ def test_exp_not_int(self, key): jwt.decode(token, key) def test_exp_datetime(self, key): - exp = datetime.utcnow() + timedelta(seconds=5) + exp = utcnow() + timedelta(seconds=5) claims = {"exp": exp} @@ -269,7 +270,7 @@ def test_exp_datetime(self, key): jwt.decode(token, key) def test_exp_with_leeway(self, key): - exp = datetime.utcnow() - timedelta(seconds=5) + exp = utcnow() - timedelta(seconds=5) claims = { "exp": exp, @@ -281,7 +282,7 @@ def test_exp_with_leeway(self, key): jwt.decode(token, key, options=options) def test_exp_in_past(self, key): - exp = datetime.utcnow() - timedelta(seconds=5) + exp = utcnow() - timedelta(seconds=5) claims = {"exp": exp} @@ -291,7 +292,7 @@ def test_exp_in_past(self, key): jwt.decode(token, key) def test_exp_skip(self, key): - exp = datetime.utcnow() - timedelta(seconds=5) + exp = utcnow() - timedelta(seconds=5) claims = {"exp": exp} @@ -504,8 +505,8 @@ def test_unverified_claims_object(self, claims, key): [ ("aud", "aud"), ("ait", "ait"), - ("exp", datetime.utcnow() + timedelta(seconds=3600)), - ("nbf", datetime.utcnow() - timedelta(seconds=5)), + ("exp", utcnow() + timedelta(seconds=3600)), + ("nbf", utcnow() - timedelta(seconds=5)), ("iss", "iss"), ("sub", "sub"), ("jti", "jti"),