Skip to content

Commit ab7fb28

Browse files
committed
Merge pull request jpadilla#56 from wbolster/issue-54
Allow datetime.timedelta for leeway arg
2 parents 1a38e31 + 880e133 commit ab7fb28

File tree

3 files changed

+34
-13
lines changed

3 files changed

+34
-13
lines changed

README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,13 @@ time.sleep(32)
151151
jwt.decode(jwt_payload, 'secret', leeway=10)
152152
```
153153

154+
Instead of specifying the leeway as a number of seconds, a `datetime.timedelta` instance can be used. The last line in the example above is equivalent to:
155+
156+
```python
157+
jwt.decode(jwt_payload, 'secret', leeway=datetime.timedelta(seconds=10))
158+
```
159+
160+
154161
### Not Before Time Claim
155162

156163
> The nbf (not before) claim identifies the time before which the JWT MUST NOT be accepted for processing. The processing of the nbf claim requires that the current date/time MUST be after or equal to the not-before date/time listed in the nbf claim. Implementers MAY provide for some small leeway, usually no more than a few minutes, to account for clock skew. Its value MUST be a number containing a NumericDate value. Use of this claim is OPTIONAL.

jwt/__init__.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
import hmac
1212
import sys
1313

14-
from datetime import datetime
14+
from datetime import datetime, timedelta
1515
from calendar import timegm
1616
from collections import Mapping
1717

@@ -359,6 +359,17 @@ def load(jwt):
359359

360360
def verify_signature(payload, signing_input, header, signature, key='',
361361
verify_expiration=True, leeway=0, **kwargs):
362+
363+
if isinstance(leeway, timedelta):
364+
try:
365+
leeway.total_seconds
366+
except AttributeError:
367+
# On Python 2.6, timedelta instances do not have
368+
# a .total_seconds() method.
369+
leeway = leeway.days * 24 * 60 * 60 + leeway.seconds
370+
else:
371+
leeway = leeway.total_seconds()
372+
362373
try:
363374
algorithm = header['alg'].upper()
364375
key = prepare_key_methods[algorithm](key)

tests/test_jwt.py

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import time
66

77
from calendar import timegm
8-
from datetime import datetime
8+
from datetime import datetime, timedelta
99
from decimal import Decimal
1010

1111
import jwt
@@ -411,20 +411,23 @@ def test_decode_with_expiration_with_leeway(self):
411411
decoded_payload, signing, header, signature = jwt.load(jwt_message)
412412

413413
# With 3 seconds leeway, should be ok
414-
jwt.decode(jwt_message, secret, leeway=3)
414+
for leeway in (3, timedelta(seconds=3)):
415+
jwt.decode(jwt_message, secret, leeway=leeway)
415416

416-
jwt.verify_signature(decoded_payload, signing, header,
417-
signature, secret, leeway=3)
417+
jwt.verify_signature(decoded_payload, signing, header,
418+
signature, secret, leeway=leeway)
418419

419420
# With 1 seconds, should fail
420-
self.assertRaises(
421-
jwt.ExpiredSignature,
422-
lambda: jwt.decode(jwt_message, secret, leeway=1))
423-
424-
self.assertRaises(
425-
jwt.ExpiredSignature,
426-
lambda: jwt.verify_signature(decoded_payload, signing,
427-
header, signature, secret, leeway=1))
421+
for leeway in (1, timedelta(seconds=1)):
422+
self.assertRaises(
423+
jwt.ExpiredSignature,
424+
lambda: jwt.decode(jwt_message, secret, leeway=leeway))
425+
426+
self.assertRaises(
427+
jwt.ExpiredSignature,
428+
lambda: jwt.verify_signature(decoded_payload, signing,
429+
header, signature, secret,
430+
leeway=leeway))
428431

429432
def test_decode_with_notbefore_with_leeway(self):
430433
self.payload['nbf'] = utc_timestamp() + 10

0 commit comments

Comments
 (0)