Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add option to provide current time when decoding JWT #267

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 33 additions & 8 deletions jose/jwt.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,17 @@ def encode(claims, key, algorithm=ALGORITHMS.HS256, headers=None, access_token=N
return jws.sign(claims, key, headers=headers, algorithm=algorithm)


def decode(token, key, algorithms=None, options=None, audience=None, issuer=None, subject=None, access_token=None):
def decode(
token,
key,
algorithms=None,
options=None,
audience=None,
issuer=None,
subject=None,
access_token=None,
now=None,
):
"""Verifies a JWT string's signature and validates reserved claims.

Args:
Expand All @@ -74,6 +84,7 @@ def decode(token, key, algorithms=None, options=None, audience=None, issuer=None
claim set, then the access_token must be included, and it must match
the "at_hash" claim.
options (dict): A dictionary of options for skipping validation steps.
now (datetime): Current time. If not set, defaults to current system time.

defaults = {
'verify_signature': True,
Expand Down Expand Up @@ -162,6 +173,7 @@ def decode(token, key, algorithms=None, options=None, audience=None, issuer=None
algorithm=algorithm,
access_token=access_token,
options=defaults,
now=now,
)

return claims
Expand Down Expand Up @@ -254,7 +266,7 @@ def _validate_iat(claims):
raise JWTClaimsError("Issued At claim (iat) must be an integer.")


def _validate_nbf(claims, leeway=0):
def _validate_nbf(now, claims, leeway=0):
"""Validates that the 'nbf' claim is valid.

The "nbf" (not before) claim identifies the time before which the JWT
Expand All @@ -266,6 +278,7 @@ def _validate_nbf(claims, leeway=0):
NumericDate value. Use of this claim is OPTIONAL.

Args:
now (datetime): Current time.
claims (dict): The claims dictionary to validate.
leeway (int): The number of seconds of skew that is allowed.
"""
Expand All @@ -278,13 +291,13 @@ 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(now.utctimetuple())

if nbf > (now + leeway):
raise JWTClaimsError("The token is not yet valid (nbf)")


def _validate_exp(claims, leeway=0):
def _validate_exp(now, claims, leeway=0):
"""Validates that the 'exp' claim is valid.

The "exp" (expiration time) claim identifies the expiration time on
Expand All @@ -296,6 +309,7 @@ def _validate_exp(claims, leeway=0):
containing a NumericDate value. Use of this claim is OPTIONAL.

Args:
now (datetime): Current time.
claims (dict): The claims dictionary to validate.
leeway (int): The number of seconds of skew that is allowed.
"""
Expand All @@ -308,7 +322,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(now.utctimetuple())

if exp < (now - leeway):
raise ExpiredSignatureError("Signature has expired.")
Expand Down Expand Up @@ -455,7 +469,16 @@ def _validate_at_hash(claims, access_token, algorithm):
raise JWTClaimsError("at_hash claim does not match access_token.")


def _validate_claims(claims, audience=None, issuer=None, subject=None, algorithm=None, access_token=None, options=None):
def _validate_claims(
claims,
audience=None,
issuer=None,
subject=None,
algorithm=None,
access_token=None,
options=None,
now=None,
):

leeway = options.get("leeway", 0)

Expand All @@ -475,10 +498,12 @@ def _validate_claims(claims, audience=None, issuer=None, subject=None, algorithm
_validate_iat(claims)

if options.get("verify_nbf"):
_validate_nbf(claims, leeway=leeway)
now = now or datetime.utcnow()
_validate_nbf(now, claims, leeway=leeway)

if options.get("verify_exp"):
_validate_exp(claims, leeway=leeway)
now = now or datetime.utcnow()
_validate_exp(now, claims, leeway=leeway)

if options.get("verify_aud"):
_validate_aud(claims, audience=audience)
Expand Down
10 changes: 10 additions & 0 deletions tests/test_jwt.py
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,16 @@ def test_exp_skip(self, key):

jwt.decode(token, key, options=options)

def test_time_travel(self, key):

nbf = datetime(2015, 10, 21, 16, 29)
now = datetime(2015, 10, 21, 18, 0)
exp = datetime(2015, 10, 21, 19, 28)
claims = {"exp": exp, "nbf": nbf}
token = jwt.encode(claims, key)

jwt.decode(token, key, now=now)

def test_aud_string(self, key):

aud = "audience"
Expand Down