[0.9.28] - OAuth/Auth with httpOnly cookie
All checks were successful
Deploy on push / deploy (push) Successful in 4m32s

This commit is contained in:
2025-09-28 12:22:37 +03:00
parent 6451ba7de5
commit fb98a1c6c8
27 changed files with 1449 additions and 2147 deletions

View File

@@ -16,6 +16,7 @@ from orm.community import Community, CommunityAuthor, CommunityFollower
from settings import (
FRONTEND_URL,
OAUTH_CLIENTS,
SESSION_COOKIE_DOMAIN,
SESSION_COOKIE_HTTPONLY,
SESSION_COOKIE_MAX_AGE,
SESSION_COOKIE_NAME,
@@ -526,48 +527,25 @@ async def oauth_callback(request: Any) -> JSONResponse | RedirectResponse:
)
)
logger.info(f"🔗 OAuth redirect URL: {final_redirect_url}")
# Создаем ответ с редиректом
response = RedirectResponse(url=final_redirect_url)
# 🔍 Диагностика перед установкой cookie
logger.info(f"🔍 Готовимся установить cookie для redirect на: {parsed_redirect.netloc}")
logger.info(f"🔍 Текущие настройки cookie: secure={SESSION_COOKIE_SECURE}, samesite={SESSION_COOKIE_SAMESITE}")
# 🍪 Устанавливаем httpOnly cookie для безопасности
# 💋 Исправляем domain для testing.discours.io - не используем wildcard domain
cookie_domain = None # Убираем wildcard domain для корректной работы
cookie_samesite = SESSION_COOKIE_SAMESITE
if "discours.io" in parsed_redirect.netloc:
# 💋 ЭКСТРЕННОЕ ИСПРАВЛЕНИЕ: Используем wildcard domain для всех discours.io
cookie_domain = ".discours.io" # Работает для всех поддоменов включая testing.discours.io
cookie_samesite = "lax" # Безопасный вариант для same-site запросов
# 💋 Принудительно включаем Secure для всех discours.io доменов (всегда HTTPS)
cookie_secure = SESSION_COOKIE_SECURE
if "discours.io" in parsed_redirect.netloc:
cookie_secure = True # Все discours.io домены используют HTTPS
# 🍪 Устанавливаем httpOnly cookie вместо токена в URL
response = RedirectResponse(url=redirect_uri, status_code=307)
response.set_cookie(
SESSION_COOKIE_NAME,
session_token,
key=SESSION_COOKIE_NAME,
value=session_token,
httponly=SESSION_COOKIE_HTTPONLY,
secure=cookie_secure,
samesite=cookie_samesite,
secure=SESSION_COOKIE_SECURE,
samesite=SESSION_COOKIE_SAMESITE if SESSION_COOKIE_SAMESITE in ["strict", "lax", "none"] else "none",
max_age=SESSION_COOKIE_MAX_AGE,
path="/", # Важно: устанавливаем path="/" для доступности cookie во всех путях
domain=cookie_domain, # Поддержка поддоменов только для основного домена
path="/",
domain=SESSION_COOKIE_DOMAIN, # ✅ Для работы с поддоменами
)
# 🔍 Дополнительная диагностика cookie
logger.warning("🚨 ВАЖНО: Cookie должен быть установлен в браузере и отправляться в последующих запросах!")
logger.warning("🚨 Если cookie не передается, проверьте:")
logger.warning(f" - Браузер принимает cookie с domain={cookie_domain}")
logger.warning(f" - HTTPS работает правильно (secure={cookie_secure})")
logger.warning(f" - SameSite политика не блокирует (samesite={cookie_samesite})")
logger.warning(" - Path='/' доступен для всех запросов")
logger.info(f"✅ OAuth: httpOnly cookie установлен для user_id={author.id}")
logger.info(f"🔗 Redirect на фронтенд БЕЗ токена в URL: {redirect_uri}")
logger.info(
f"🍪 Cookie: {SESSION_COOKIE_NAME}, secure={SESSION_COOKIE_SECURE}, samesite={SESSION_COOKIE_SAMESITE}"
)
logger.info(f"OAuth успешно завершен для {provider}, user_id={author.id}")
return response
@@ -883,55 +861,30 @@ async def oauth_callback_http(request: Request) -> JSONResponse | RedirectRespon
logger.info(f" - Provider: {provider}")
logger.info(f" - User ID: {author.id}")
# Возвращаем redirect с токеном в URL
response = RedirectResponse(url=final_redirect_url, status_code=307)
# 🍪 Устанавливаем httpOnly cookie для безопасности
# 💋 Исправляем domain для testing.discours.io - не используем wildcard domain
cookie_domain = None # Убираем wildcard domain для корректной работы
cookie_samesite = SESSION_COOKIE_SAMESITE
if "discours.io" in parsed_redirect.netloc:
# 💋 ЭКСТРЕННОЕ ИСПРАВЛЕНИЕ: Используем wildcard domain для всех discours.io
cookie_domain = ".discours.io" # Работает для всех поддоменов включая testing.discours.io
cookie_samesite = "lax" # Безопасный вариант для same-site запросов
# 💋 Принудительно включаем Secure для всех discours.io доменов (всегда HTTPS)
cookie_secure = SESSION_COOKIE_SECURE
if "discours.io" in parsed_redirect.netloc:
cookie_secure = True # Все discours.io домены используют HTTPS
# 🍪 Устанавливаем httpOnly cookie вместо токена в URL
response = RedirectResponse(url=redirect_uri, status_code=307)
response.set_cookie(
SESSION_COOKIE_NAME,
session_token,
key=SESSION_COOKIE_NAME,
value=session_token,
httponly=SESSION_COOKIE_HTTPONLY,
secure=cookie_secure,
samesite=cookie_samesite,
secure=SESSION_COOKIE_SECURE,
samesite=SESSION_COOKIE_SAMESITE,
max_age=SESSION_COOKIE_MAX_AGE,
path="/", # Важно: устанавливаем path="/" для доступности cookie во всех путях
domain=cookie_domain, # Поддержка поддоменов только для основного домена
path="/",
domain=SESSION_COOKIE_DOMAIN, # ✅ Для работы с поддоменами
)
logger.info(f"✅ OAuth: httpOnly cookie установлен для user_id={author.id}")
logger.info(f"🔗 Redirect на фронтенд БЕЗ токена в URL: {redirect_uri}")
logger.info(
f"🍪 Cookie установлен: name={SESSION_COOKIE_NAME}, domain={cookie_domain}, secure={cookie_secure}, samesite={cookie_samesite}"
)
logger.info(
f"🔍 Cookie debug: redirect_netloc={parsed_redirect.netloc}, is_testing={('testing.discours.io' in parsed_redirect.netloc)}"
f"🍪 Cookie: {SESSION_COOKIE_NAME}, secure={SESSION_COOKIE_SECURE}, samesite={SESSION_COOKIE_SAMESITE}"
)
logger.info(
f"🔍 Session token preview: {session_token[:30]}..."
if len(session_token) > 30
else f"🔍 Session token: {session_token}"
)
logger.info(f"🔗 Final redirect: {final_redirect_url}")
# 🔍 Дополнительная диагностика cookie
logger.warning("🚨 ВАЖНО: Cookie должен быть установлен в браузере и отправляться в последующих запросах!")
logger.warning("🚨 Если cookie не передается, проверьте:")
logger.warning(f" - Браузер принимает cookie с domain={cookie_domain}")
logger.warning(f" - HTTPS работает правильно (secure={cookie_secure})")
logger.warning(f" - SameSite политика не блокирует (samesite={cookie_samesite})")
logger.warning(" - Path='/' доступен для всех запросов")
logger.info(f"✅ OAuth успешно завершен для {provider}, user_id={author.id}")
return response