-
Notifications
You must be signed in to change notification settings - Fork 812
Description
Describe the bug
Hi friends, this is related to #1291. The problem is mixing timezone-naive and timezone-aware datetime operations in the _get_token_from_authentication_server
method in the oauth2_validators
module. Below are the steps
Step 1: Naive Timestamp Creation (Lines 407-409)
django-oauth-toolkit/oauth2_provider/oauth2_validators.py
Lines 405 to 407 in 0a5ffdb
max_caching_time = datetime.now() + timedelta( | |
seconds=oauth2_settings.RESOURCE_SERVER_TOKEN_CACHING_SECONDS | |
) |
- datetime.now() creates a timezone-naive timestamp using the system's local time
- On my Eastern Time machine, this would be something like 2025-09-02 16:06:00 (4:06 PM ET)
- This timestamp has no timezone information attached to it
Step 2: Expires Assignment (Lines 409-414)
django-oauth-toolkit/oauth2_provider/oauth2_validators.py
Lines 409 to 414 in 0a5ffdb
if "exp" in content: | |
expires = datetime.utcfromtimestamp(content["exp"]) | |
if expires > max_caching_time: | |
expires = max_caching_time | |
else: | |
expires = max_caching_time |
- When there's no "exp" in the token content, expires gets set to the naive max_caching_time
- Since the default RESOURCE_SERVER_TOKEN_CACHING_SECONDS is 300 seconds (5 minutes), this code path is frequently taken
- Note any well-behaved OAuth provider will provide exp as UTC
Step 3: Timezone Conversion (Lines 418-421)
django-oauth-toolkit/oauth2_provider/oauth2_validators.py
Lines 418 to 421 in 0a5ffdb
if settings.USE_TZ: | |
expires = make_aware( | |
expires, timezone=get_timezone(oauth2_settings.AUTHENTICATION_SERVER_EXP_TIME_ZONE) | |
) |
- make_aware() treats the naive timestamp as if it were in the specified timezone
- oauth2_settings.AUTHENTICATION_SERVER_EXP_TIME_ZONE defaults to UTC
- My Eastern Time timestamp (4:06 PM ET) gets interpreted as 4:06 PM UTC
- This effectively makes the token expire 4-5 hours earlier than intended (depending on EST/EDT)
As I understand it, the naive datetime creation is the primary cause. We should either use UTC, datetime.utcnow()
for the max_caching_time
or Django's timezone.now()
.
I may be missing something, so please correct me if I am!
To Reproduce
Validate an external OAuth Provider token on a non-UTC host. In my example I am running the resource provider on a Windows machine whose system clock is in Eastern Time (-4 thanks to day light savings).
Expected behavior
When a token expires in the feature, and the max caching time is 5 minutes, the token should be valid.
Version
3.0.1
- I have tested with the latest published release and it's still a problem.
- I have tested with the master branch and it's still a problem.