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

use UTC instead of computer timezone to check exp, nbf and other time-related claims #297

Open
daweedm opened this issue Sep 5, 2022 · 2 comments

Comments

@daweedm
Copy link

daweedm commented Sep 5, 2022

In jwt.py, among others checks which focus on time-related claims, jwcrypto uses a "timezoned" time (time.time()) in order to process the checks :

        if self._check_claims is None:
            if 'exp' in claims:
                self._check_exp(claims['exp'], time.time(), self._leeway)
            if 'nbf' in claims:
                self._check_nbf(claims['nbf'], time.time(), self._leeway)

this approach causes issues when using jwcrypto with a server having a timezone that is different of a client.

I think we should use datetime.utcnow() by default instead, what do you think about it ?

I can make a PR if needed.

@simo5
Copy link
Member

simo5 commented Sep 5, 2022

Yeah, we should definitely always use UTC.
A PR is definitely welcome, the question is how to upgrade w/o breaking currently working servers as a side effect ...

@Flat-Irons
Copy link

Actually, time.time() is UTC. The confusion most likely stems from comparing timestamps from datetime.datetime.utcnow() vs datetime.datetime.now()

I'm currently in EDT, so UTC-04.

Running the code below:

import datetime
import time


print("time.time():                ", time.time())
print("datetime.datetime.utcnow(): ", datetime.datetime.utcnow().timestamp())
print("datetime.datetime.now():    ", datetime.datetime.now().timestamp())
print("datetime.datetime.utcnow(): ", datetime.datetime.utcnow())
print("datetime.datetime.now():    ", datetime.datetime.now())

Gives us:

time.time():                 1687834846.4905422
datetime.datetime.utcnow():  1687849246.490579
datetime.datetime.now():     1687834846.490584
datetime.datetime.utcnow():  2023-06-27 03:00:46.490598
datetime.datetime.now():     2023-06-26 23:00:46.490612

The time.time() and datetime.datetime.now() are the same which makes it seem as though time.time() is giving us local time.

Running the below code instead:

import datetime
import time


print("time.time():                ", time.time())
print("datetime.datetime.utcnow(): ", datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).timestamp())
print("datetime.datetime.now():    ", datetime.datetime.now().replace(tzinfo=datetime.timezone.utc).timestamp())
print("datetime.datetime.utcnow(): ", datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc))
print("datetime.datetime.now():    ", datetime.datetime.now().replace(tzinfo=datetime.timezone.utc))

Gives us:

time.time():                 1687832852.3228416
datetime.datetime.utcnow():  1687832852.322877
datetime.datetime.now():     1687818452.322895
datetime.datetime.utcnow():  2023-06-27 02:27:32.322908+00:00
datetime.datetime.now():     2023-06-26 22:27:32.322923+00:00

Here we can see that time.time() and datetime.datetime.utcnow() are the same which is what we desire.

This happens because the datetime.timestamp() function, as according to the Python docs, assumes any timezone naive datetime objects are in local time and converts them to UTC, and both datetime.datetime.now() and datetime.datetime.utcnow() are timezone naive objects. Hence why we made them timezone aware in the second example.

It's worth noting that in my example, I incorrectly labeled my current local time from datetime.datetime.now() as UTC to demonstrate the point better, but obviously, if we had the correct timezone on it, then it would give the same timestamp as time.time()

See:

import datetime
import time

from pytz import timezone


print("time.time():                ", time.time())
print("datetime.datetime.utcnow(): ", datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).timestamp())
print("datetime.datetime.now():    ", datetime.datetime.now(timezone('US/Eastern')).timestamp())
print("datetime.datetime.utcnow(): ", datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc))
print("datetime.datetime.now():    ", datetime.datetime.now(timezone('US/Eastern')))

Gives us:

time.time():                 1687836103.5745661
datetime.datetime.utcnow():  1687836103.574606
datetime.datetime.now():     1687836103.578064
datetime.datetime.utcnow():  2023-06-27 03:21:43.578093+00:00
datetime.datetime.now():     2023-06-26 23:21:43.578112-04:00

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants