Skip to content

Commit

Permalink
Merge pull request #56 from wbolster/issue-54
Browse files Browse the repository at this point in the history
Allow datetime.timedelta for leeway arg
  • Loading branch information
jpadilla committed Jan 5, 2015
2 parents 1a38e31 + 880e133 commit ab7fb28
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 13 deletions.
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,13 @@ time.sleep(32)
jwt.decode(jwt_payload, 'secret', leeway=10)
```

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:

```python
jwt.decode(jwt_payload, 'secret', leeway=datetime.timedelta(seconds=10))
```


### Not Before Time Claim

> 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.
Expand Down
13 changes: 12 additions & 1 deletion jwt/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
import hmac
import sys

from datetime import datetime
from datetime import datetime, timedelta
from calendar import timegm
from collections import Mapping

Expand Down Expand Up @@ -359,6 +359,17 @@ def load(jwt):

def verify_signature(payload, signing_input, header, signature, key='',
verify_expiration=True, leeway=0, **kwargs):

if isinstance(leeway, timedelta):
try:
leeway.total_seconds
except AttributeError:
# On Python 2.6, timedelta instances do not have
# a .total_seconds() method.
leeway = leeway.days * 24 * 60 * 60 + leeway.seconds
else:
leeway = leeway.total_seconds()

try:
algorithm = header['alg'].upper()
key = prepare_key_methods[algorithm](key)
Expand Down
27 changes: 15 additions & 12 deletions tests/test_jwt.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import time

from calendar import timegm
from datetime import datetime
from datetime import datetime, timedelta
from decimal import Decimal

import jwt
Expand Down Expand Up @@ -411,20 +411,23 @@ def test_decode_with_expiration_with_leeway(self):
decoded_payload, signing, header, signature = jwt.load(jwt_message)

# With 3 seconds leeway, should be ok
jwt.decode(jwt_message, secret, leeway=3)
for leeway in (3, timedelta(seconds=3)):
jwt.decode(jwt_message, secret, leeway=leeway)

jwt.verify_signature(decoded_payload, signing, header,
signature, secret, leeway=3)
jwt.verify_signature(decoded_payload, signing, header,
signature, secret, leeway=leeway)

# With 1 seconds, should fail
self.assertRaises(
jwt.ExpiredSignature,
lambda: jwt.decode(jwt_message, secret, leeway=1))

self.assertRaises(
jwt.ExpiredSignature,
lambda: jwt.verify_signature(decoded_payload, signing,
header, signature, secret, leeway=1))
for leeway in (1, timedelta(seconds=1)):
self.assertRaises(
jwt.ExpiredSignature,
lambda: jwt.decode(jwt_message, secret, leeway=leeway))

self.assertRaises(
jwt.ExpiredSignature,
lambda: jwt.verify_signature(decoded_payload, signing,
header, signature, secret,
leeway=leeway))

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

0 comments on commit ab7fb28

Please sign in to comment.