jpadilla / pyjwt

JSON Web Token implementation in Python
https://pyjwt.readthedocs.io
MIT License
5.08k stars 679 forks source link

Possible incorrect behavior of verifying `exp` claim when `exp` == `datetime.now()` #796

Closed wcedmisten-reify closed 1 year ago

wcedmisten-reify commented 2 years ago

When validating the exp claim, pyjwt checks if exp < (now - leeway), and throws an error if so. I would expect this condition to be exp <= (now - leeway).

https://github.com/jpadilla/pyjwt/blob/master/jwt/api_jwt.py#L233-L234

The RFC describes the expiration claim:

The "exp" (expiration time) claim identifies the expiration time on or after which the JWT MUST NOT be accepted for processing.

which is a bit ambiguous. But also says:

The processing of the "exp" claim requires that the current date/time MUST be before the expiration date/time listed in the "exp" claim.

Which seems more concrete.

Expected Result

When exp == datetime.now(), throw a validation error for exp

Actual Result

A validation error is not thrown until the next second.

Reproduction Steps

import jwt
import time
import datetime
from datetime import timezone

jwt_payload = jwt.encode(
    {"exp": datetime.datetime.now(tz=timezone.utc) },
    "secret",
)

# does not throw an exception
jwt.decode(jwt_payload, "secret", leeway=0, algorithms=["HS256"])
jwt_payload = jwt.encode(
    {"exp": datetime.datetime.now(tz=timezone.utc) },
    "secret",
)

time.sleep(1)

# throws jwt.exceptions.ExpiredSignatureError: Signature has expired
jwt.decode(jwt_payload, "secret", leeway=0, algorithms=["HS256"])

System Information

$ python3 -m jwt.help
{
  "cryptography": {
    "version": ""
  },
  "implementation": {
    "name": "CPython",
    "version": "3.9.13"
  },
  "platform": {
    "release": "21.6.0",
    "system": "Darwin"
  },
  "pyjwt": {
    "version": "2.4.0"
  }
}