Skip to content

Commit 40831dc

Browse files
committed
fix(oauth2): Handle SESSION_COOKIE_SAMESITE = 'Strict'
1 parent f0c6828 commit 40831dc

File tree

5 files changed

+79
-0
lines changed

5 files changed

+79
-0
lines changed

ChangeLog.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ Note worthy changes
3434
- Added a new setting, ``SOCIALACCOUNT_ONLY``, which when set to ``True``,
3535
disables all functionality with respect to local accounts.
3636

37+
- The OAuth2 handshake was not working properly in case of
38+
``SESSION_COOKIE_SAMESITE = "Strict"``, fixed.
39+
3740

3841
0.61.1 (2024-02-09)
3942
*******************

allauth/socialaccount/providers/oauth2/tests/__init__.py

Whitespace-only changes.
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
from django.urls import reverse
2+
3+
import pytest
4+
from pytest_django.asserts import assertTemplateUsed
5+
6+
7+
@pytest.mark.parametrize(
8+
"samesite_strict,did_already_redirect,expect_redirect",
9+
[
10+
(True, False, True),
11+
(True, True, False),
12+
(False, False, False),
13+
],
14+
)
15+
def test_samesite_strict(
16+
client,
17+
samesite_strict,
18+
settings,
19+
google_provier_settings,
20+
did_already_redirect,
21+
expect_redirect,
22+
db,
23+
):
24+
settings.SESSION_COOKIE_SAMESITE = "Strict" if samesite_strict else "Lax"
25+
query = "?state=123"
26+
resp = client.get(
27+
reverse("google_callback") + query + ("&_redir" if did_already_redirect else "")
28+
)
29+
if expect_redirect:
30+
assertTemplateUsed(resp, "socialaccount/login_redirect.html")
31+
assert (
32+
resp.context["redirect_to"]
33+
== reverse("google_callback") + query + "&_redir="
34+
)
35+
else:
36+
assertTemplateUsed(resp, "socialaccount/authentication_error.html")

allauth/socialaccount/providers/oauth2/views.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
from datetime import timedelta
22
from requests import RequestException
33

4+
from django.conf import settings
45
from django.core.exceptions import PermissionDenied
6+
from django.shortcuts import render
57
from django.urls import reverse
68
from django.utils import timezone
79

10+
from allauth.account import app_settings as account_settings
811
from allauth.core.exceptions import ImmediateHttpResponse
12+
from allauth.core.internal.httpkit import add_query_params
913
from allauth.socialaccount.adapter import get_adapter
1014
from allauth.socialaccount.helpers import (
1115
complete_social_login,
@@ -156,6 +160,24 @@ def dispatch(self, request, *args, **kwargs):
156160
request, provider, exception=e, extra_context={"state": state}
157161
)
158162

163+
def _redirect_strict_samesite(self, request, provider):
164+
if (
165+
"_redir" in request.GET
166+
or settings.SESSION_COOKIE_SAMESITE.lower() != "strict"
167+
or request.method != "GET"
168+
):
169+
return
170+
redirect_to = request.get_full_path()
171+
redirect_to = add_query_params(redirect_to, {"_redir": ""})
172+
return render(
173+
request,
174+
"socialaccount/login_redirect." + account_settings.TEMPLATE_EXTENSION,
175+
{
176+
"provider": provider,
177+
"redirect_to": redirect_to,
178+
},
179+
)
180+
159181
def _get_state(self, request, provider):
160182
state = None
161183
state_id = get_request_param(request, "state")
@@ -165,6 +187,11 @@ def _get_state(self, request, provider):
165187
else:
166188
state = statekit.unstash_last_state(request)
167189
if state is None:
190+
resp = self._redirect_strict_samesite(request, provider)
191+
if resp:
192+
# 'Strict' is in effect, let's try a redirect and then another
193+
# shot at finding our state...
194+
return None, resp
168195
return None, render_authentication_error(
169196
request,
170197
provider,
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<!DOCTYPE html>
2+
<html>
3+
{% load i18n %}
4+
<head>
5+
<title>{% translate "Sign In" %} | {{ provider }}</title>
6+
<meta http-equiv="refresh" content="0;URL='{{ redirect_to }}'" />
7+
</head>
8+
<body>
9+
<p>
10+
<a href="{{ redirect_to }}">{% translate "Continue" %}</a>
11+
</p>
12+
</body>
13+
</html>

0 commit comments

Comments
 (0)