Cross-Site cookies enabled

This commit is contained in:
ValueOn AG 2026-05-08 13:58:12 +02:00
parent 130bdfb7cc
commit 35693a61e3

View file

@ -24,6 +24,11 @@ REFRESH_TOKEN_EXPIRE_DAYS = int(APP_CONFIG.get("APP_REFRESH_TOKEN_EXPIRY", "7"))
APP_API_URL = APP_CONFIG.get("APP_API_URL", "http://localhost:8000")
USE_SECURE_COOKIES = APP_API_URL.startswith("https://") if APP_API_URL else False
# Cross-origin SPA (any host) + API (gateway host): SameSite=None + Secure is required so the
# browser sends cookies on credentialed XHR/fetch. HTTP localhost uses Lax (None without Secure is rejected).
COOKIE_SAMESITE = "none" if USE_SECURE_COOKIES else "lax"
COOKIE_SAMESITE_SET_COOKIE = "None" if USE_SECURE_COOKIES else "Lax"
def createAccessToken(data: dict, expiresDelta: Optional[timedelta] = None) -> Tuple[str, "datetime"]:
"""Create a JWT access token and return (token, expiresAt)."""
@ -60,7 +65,7 @@ def setAccessTokenCookie(response: Response, token: str, expiresDelta: Optional[
value=token,
httponly=True,
secure=USE_SECURE_COOKIES, # Only secure in production (HTTPS)
samesite="strict",
samesite=COOKIE_SAMESITE,
path="/",
max_age=maxAge
)
@ -73,7 +78,7 @@ def setRefreshTokenCookie(response: Response, token: str) -> None:
value=token,
httponly=True,
secure=USE_SECURE_COOKIES, # Only secure in production (HTTPS)
samesite="strict",
samesite=COOKIE_SAMESITE,
path="/",
max_age=REFRESH_TOKEN_EXPIRE_DAYS * 24 * 60 * 60
)
@ -90,11 +95,17 @@ def clearAccessTokenCookie(response: Response) -> None:
# Primary method: Raw Set-Cookie header for guaranteed deletion
response.headers.append(
"Set-Cookie",
f"auth_token=deleted; Path=/; Max-Age=0; Expires=Thu, 01 Jan 1970 00:00:00 GMT; HttpOnly{secure_flag}; SameSite=Strict"
f"auth_token=deleted; Path=/; Max-Age=0; Expires=Thu, 01 Jan 1970 00:00:00 GMT; HttpOnly{secure_flag}; SameSite={COOKIE_SAMESITE_SET_COOKIE}"
)
# Fallback: Also use FastAPI's built-in method
response.delete_cookie(key="auth_token", path="/")
# Fallback: Also use FastAPI's built-in method (match SameSite/Secure for invalidation)
response.delete_cookie(
key="auth_token",
path="/",
secure=USE_SECURE_COOKIES,
httponly=True,
samesite=COOKIE_SAMESITE,
)
def clearRefreshTokenCookie(response: Response) -> None:
@ -108,10 +119,16 @@ def clearRefreshTokenCookie(response: Response) -> None:
# Primary method: Raw Set-Cookie header for guaranteed deletion
response.headers.append(
"Set-Cookie",
f"refresh_token=deleted; Path=/; Max-Age=0; Expires=Thu, 01 Jan 1970 00:00:00 GMT; HttpOnly{secure_flag}; SameSite=Strict"
f"refresh_token=deleted; Path=/; Max-Age=0; Expires=Thu, 01 Jan 1970 00:00:00 GMT; HttpOnly{secure_flag}; SameSite={COOKIE_SAMESITE_SET_COOKIE}"
)
# Fallback: Also use FastAPI's built-in method
response.delete_cookie(key="refresh_token", path="/")
# Fallback: Also use FastAPI's built-in method (match SameSite/Secure for invalidation)
response.delete_cookie(
key="refresh_token",
path="/",
secure=USE_SECURE_COOKIES,
httponly=True,
samesite=COOKIE_SAMESITE,
)