Skip to content

Commit a751f80

Browse files
committed
fix: Anti csrf should happen only when access token is passed
1 parent 90ccc1b commit a751f80

File tree

2 files changed

+64
-4
lines changed

2 files changed

+64
-4
lines changed

supertokens_python/recipe/session/session_request_functions.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,8 @@ async def get_session_from_request(
153153
do_anti_csrf_check = normalise_http_method(request.method()) != "get"
154154
if request_transfer_method == "header":
155155
do_anti_csrf_check = False
156+
if request_access_token is None:
157+
do_anti_csrf_check = False
156158

157159
if do_anti_csrf_check and config.anti_csrf == "VIA_CUSTOM_HEADER":
158160
if config.anti_csrf == "VIA_CUSTOM_HEADER":

tests/test_session.py

Lines changed: 62 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,12 @@
1313
# under the License.
1414

1515
from datetime import datetime, timedelta
16-
from typing import Any, Dict, List
16+
from typing import Any, Dict, List, Optional
1717
from unittest.mock import MagicMock
1818

19-
from fastapi import FastAPI
19+
from fastapi import FastAPI, Depends
2020
from fastapi.requests import Request
21+
from fastapi.responses import JSONResponse
2122
from fastapi.testclient import TestClient
2223
from pytest import fixture, mark
2324

@@ -41,7 +42,10 @@
4142
merge_into_access_token_payload,
4243
update_session_data_in_database,
4344
)
44-
from supertokens_python.recipe.session.interfaces import RecipeInterface
45+
from supertokens_python.recipe.session.interfaces import (
46+
RecipeInterface,
47+
SessionContainer,
48+
)
4549
from supertokens_python.recipe.session.jwt import (
4650
parse_jwt_without_signature_verification,
4751
)
@@ -52,6 +56,7 @@
5256
refresh_session,
5357
revoke_session,
5458
)
59+
from supertokens_python.recipe.session.framework.fastapi import verify_session
5560
from tests.utils import clean_st, reset, setup_st, start_st
5661

5762
pytestmark = mark.asyncio
@@ -251,6 +256,13 @@ async def create_api(request: Request): # type: ignore
251256
await async_create_new_session(request, "test-user", {}, {})
252257
return ""
253258

259+
@app.post("/sessioninfo-optional")
260+
async def _session_info(s: Optional[SessionContainer] = Depends(verify_session(session_required=False))): # type: ignore
261+
if s is not None:
262+
return JSONResponse({"session": s.get_handle(), "user_id": s.get_user_id()})
263+
else:
264+
return JSONResponse({"message": "no session"})
265+
254266
return TestClient(app)
255267

256268

@@ -707,7 +719,7 @@ async def test_that_verify_session_doesnt_always_call_core():
707719
assert session3.refresh_token is not None
708720

709721
assert (
710-
AllowedProcessStates.CALLING_SERVICE_IN_VERIFY
722+
AllowedProcessStates.CALLING_SERVICE_IN_VERIFYG
711723
not in ProcessState.get_instance().history
712724
)
713725

@@ -724,3 +736,49 @@ async def test_that_verify_session_doesnt_always_call_core():
724736
AllowedProcessStates.CALLING_SERVICE_IN_VERIFY
725737
in ProcessState.get_instance().history
726738
) # Core got called this time
739+
740+
741+
async def test_anti_csrf_header_via_custom_header_check_happens_only_when_access_token_is_provided(
742+
driver_config_client: TestClient,
743+
):
744+
args = get_st_init_args([session.init(anti_csrf="VIA_CUSTOM_HEADER", get_token_transfer_method=lambda *_: "cookie")]) # type: ignore
745+
init(**args) # type: ignore
746+
start_st()
747+
748+
response = driver_config_client.post("/create")
749+
assert response.status_code == 200
750+
751+
# With access token:
752+
# without RID:
753+
response = driver_config_client.post("/sessioninfo-optional")
754+
assert response.status_code == 401
755+
assert response.json() == {"message": "try refresh token"}
756+
757+
# with RID:
758+
response = driver_config_client.post(
759+
"/sessioninfo-optional",
760+
headers={
761+
"rid": "session",
762+
},
763+
)
764+
assert response.status_code == 200
765+
assert list(response.json()) == ["session", "user_id"]
766+
767+
# Clear access tokens:
768+
driver_config_client.cookies.clear()
769+
770+
# Without access tokens:
771+
# without RID:
772+
response = driver_config_client.post("/sessioninfo-optional")
773+
assert response.status_code == 200
774+
assert response.json() == {"message": "no session"}
775+
776+
# with RID:
777+
response = driver_config_client.post(
778+
"/sessioninfo-optional",
779+
headers={
780+
"rid": "session",
781+
},
782+
)
783+
assert response.status_code == 200
784+
assert response.json() == {"message": "no session"}

0 commit comments

Comments
 (0)