Spaces:
Running
Running
Update api/routers/auth.py
Browse files- api/routers/auth.py +17 -4
api/routers/auth.py
CHANGED
|
@@ -5,11 +5,12 @@ import os
|
|
| 5 |
import secrets
|
| 6 |
from datetime import datetime, timedelta
|
| 7 |
from typing import Dict, Optional
|
| 8 |
-
from fastapi import APIRouter, HTTPException, Response, Cookie, Form
|
| 9 |
from fastapi.responses import JSONResponse
|
| 10 |
from pydantic import BaseModel
|
| 11 |
from itsdangerous import URLSafeTimedSerializer, BadSignature, SignatureExpired
|
| 12 |
import logging
|
|
|
|
| 13 |
|
| 14 |
logger = logging.getLogger(__name__)
|
| 15 |
|
|
@@ -92,6 +93,7 @@ def verify_credentials(username: str, password: str) -> bool:
|
|
| 92 |
@router.post("/login", response_model=LoginResponse)
|
| 93 |
async def login(
|
| 94 |
response: Response,
|
|
|
|
| 95 |
username: str = Form(...),
|
| 96 |
password: str = Form(...)
|
| 97 |
):
|
|
@@ -107,13 +109,24 @@ async def login(
|
|
| 107 |
token = create_session(username)
|
| 108 |
|
| 109 |
# Set secure cookie
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 110 |
response.set_cookie(
|
| 111 |
key="session_token",
|
| 112 |
value=token,
|
| 113 |
httponly=True,
|
| 114 |
max_age=SESSION_MAX_AGE,
|
| 115 |
-
samesite=
|
| 116 |
-
secure=
|
| 117 |
)
|
| 118 |
|
| 119 |
logger.info(f"Successful login for user: {username}")
|
|
@@ -171,4 +184,4 @@ async def status(session_token: Optional[str] = Cookie(None)):
|
|
| 171 |
return {
|
| 172 |
"authenticated": session_data is not None,
|
| 173 |
"username": session_data.get("username") if session_data else None
|
| 174 |
-
}
|
|
|
|
| 5 |
import secrets
|
| 6 |
from datetime import datetime, timedelta
|
| 7 |
from typing import Dict, Optional
|
| 8 |
+
from fastapi import APIRouter, HTTPException, Response, Cookie, Form, Request
|
| 9 |
from fastapi.responses import JSONResponse
|
| 10 |
from pydantic import BaseModel
|
| 11 |
from itsdangerous import URLSafeTimedSerializer, BadSignature, SignatureExpired
|
| 12 |
import logging
|
| 13 |
+
from urllib.parse import urlparse
|
| 14 |
|
| 15 |
logger = logging.getLogger(__name__)
|
| 16 |
|
|
|
|
| 93 |
@router.post("/login", response_model=LoginResponse)
|
| 94 |
async def login(
|
| 95 |
response: Response,
|
| 96 |
+
request: Request,
|
| 97 |
username: str = Form(...),
|
| 98 |
password: str = Form(...)
|
| 99 |
):
|
|
|
|
| 109 |
token = create_session(username)
|
| 110 |
|
| 111 |
# Set secure cookie
|
| 112 |
+
# In development (HTTP), use lax samesite and secure=False
|
| 113 |
+
# In production (HTTPS), use none samesite and secure=True
|
| 114 |
+
is_production = os.getenv("ENVIRONMENT", "development") == "production"
|
| 115 |
+
|
| 116 |
+
origin = request.headers.get("origin")
|
| 117 |
+
parsed_origin = urlparse(origin) if origin else None
|
| 118 |
+
is_cross_site = bool(parsed_origin and parsed_origin.hostname and parsed_origin.hostname != request.url.hostname)
|
| 119 |
+
is_https = request.url.scheme == "https"
|
| 120 |
+
samesite = "none" if (is_https and (is_production or is_cross_site)) else "lax"
|
| 121 |
+
secure = True if samesite == "none" else is_production
|
| 122 |
+
|
| 123 |
response.set_cookie(
|
| 124 |
key="session_token",
|
| 125 |
value=token,
|
| 126 |
httponly=True,
|
| 127 |
max_age=SESSION_MAX_AGE,
|
| 128 |
+
samesite=samesite,
|
| 129 |
+
secure=secure
|
| 130 |
)
|
| 131 |
|
| 132 |
logger.info(f"Successful login for user: {username}")
|
|
|
|
| 184 |
return {
|
| 185 |
"authenticated": session_data is not None,
|
| 186 |
"username": session_data.get("username") if session_data else None
|
| 187 |
+
}
|