Opened 20 months ago
Closed 20 months ago
#35340 closed Uncategorized (invalid)
Why does Django add 1 second to the lifetime of a cookie?
| Reported by: | Leonid | Owned by: | nobody |
|---|---|---|---|
| Component: | HTTP handling | Version: | 5.0 |
| Severity: | Normal | Keywords: | cookies |
| Cc: | Leonid | Triage Stage: | Unreviewed |
| Has patch: | no | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | no |
| Easy pickings: | no | UI/UX: | no |
Description
I'm trying to implement JWT authentication using django-graphql-jwt on the backend, and nuxt3 for the frontend. My token and refresh_token are stored in cookies, and I wrapped the GraphQLView in a jwt_cookie decorator that automatically checks for the existence of the jwt token in the cookie, as well as its validity.
In general, everything works great. When I send an authorization request, the backend returns me the "Set-Cookie" headers for JWT and JWT_REFRESH_TOKEN with an expiration date that automatically deletes them as soon as they become invalid, which saves me a lot of code/logic on the frontend.
However, there is one very unpleasant thing - Django adds 1 second to the cookie lifetime for some reason in the set_cookie function, and it ruins everything. Here is the Django code:
def set_cookie(
self,
key,
value="",
max_age=None,
expires=None,
path="/",
domain=None,
secure=False,
httponly=False,
samesite=None,
):
self.cookies[key] = value
if expires is not None:
if isinstance(expires, datetime.datetime):
if timezone.is_naive(expires):
expires = timezone.make_aware(expires, datetime.timezone.utc)
delta = expires - datetime.datetime.now(tz=datetime.timezone.utc)
# Add one second so the date matches exactly (a fraction of
# time gets lost between converting to a timedelta and
# then the date string).
# Here's what I mean ↓↓↓
delta += datetime.timedelta(seconds=1)
# Just set max_age - the max_age logic will set expires.
expires = None
if max_age is not None:
raise ValueError("'expires' and 'max_age' can't be used together.")
max_age = max(0, delta.days * 86400 + delta.seconds)
else:
self.cookies[key]["expires"] = expires
else:
...
I see the comment from Django, but I still don't understand what it means.
This may not be a critical issue, but I just can't understand why they did it. The result of this behavior is that within 1 second after the token has expired, it is still in the user's cookies, and that doesn't seem right to me.
I can fix this problem by subtracting 1 second when creating cookies, but I would like to avoid unpredictable errors that may arise due to this innovation.
I would appreciate your answers and explanations :)
Issue trackers are for reporting bugs, please don't seek assistance here. You can get help from friendly community members on Discord or the forum 👍 https://www.djangoproject.com/community/