Last active
April 28, 2022 15:56
-
-
Save acu192/315d27f8fe9ff58638c3571c91c4d1ca to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from django.conf import settings | |
def SessionCookieSameSiteWorkaround(get_response): | |
def middleware(request): | |
# See: | |
# https://blog.chromium.org/2019/10/developers-get-ready-for-new.html | |
# https://github.com/django/django/pull/11894 | |
# https://web.dev/samesite-cookie-recipes/#handling-incompatible-clients | |
# https://www.chromium.org/updates/same-site/incompatible-clients | |
# | |
# TLDR: Chrome (and soon Firefox and Safari) require that you set SameSite=None | |
# in order to have a cookie set cross-domain. The old behavior of SameSite | |
# being 'None' by default is no more. The new default is 'Lax'. | |
# The issue is that we can't just set SameSite=None and be done with it, | |
# because some older browsers will break with this. Therefore we devise | |
# a two-cookie approach: one that does the new behavior of setting | |
# SameSite=None, and the second is the "legacy" cookie which relies on | |
# the old-default's behavior. If we receive only the legacy cookie in | |
# a request, we know we're dealing with one of those older browsers, | |
# and we can repair the lost cookie before proceeding to process the | |
# request. | |
cookie = settings.SESSION_COOKIE_NAME | |
legacy = "{}_legacy".format(cookie) | |
if legacy in request.COOKIES: | |
if cookie not in request.COOKIES: | |
request.COOKIES[cookie] = request.COOKIES[legacy] | |
del request.COOKIES[legacy] | |
response = get_response(request) | |
if cookie in response.cookies: | |
response.cookies[legacy] = response.cookies[cookie].value | |
response.cookies[legacy].update(response.cookies[cookie]) # <-- set Expiry, Path, etc. | |
response.cookies[cookie]['samesite'] = 'None' | |
if settings.SESSION_COOKIE_SECURE and not response.cookies[cookie].get('secure', False): | |
# Fix Django's silly `delete_cookie()` behavior which doesn't set `secure` correctly. | |
response.cookies[cookie]['secure'] = True | |
return response | |
return middleware |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
2020-05-12 update: I added lines 37-39 above, to fix an issue I noticed where Django doesn't set the
secure
flag when it deletes cookies. This caused the cookies to not be deleted by the browser (thus users couldn't log out). Anyway, all fixed now.