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
{
"cryptography": {
"version": ""
},
"implementation": {
"name": "CPython",
"version": "3.9.13"
},
"platform": {
"release": "21.6.0",
"system": "Darwin"
},
"pyjwt": {
"version": "2.4.0"
}
}
When validating the
expclaim, pyjwt checks ifexp < (now - leeway), and throws an error if so. I would expect this condition to beexp <= (now - leeway).https://github.com/jpadilla/pyjwt/blob/master/jwt/api_jwt.py#L233-L234
The RFC describes the expiration claim:
which is a bit ambiguous. But also says:
Which seems more concrete.
Expected Result
When
exp==datetime.now(), throw a validation error forexpActual Result
A validation error is not thrown until the next second.
Reproduction Steps
System Information