Spaces:
Sleeping
Sleeping
'changes'
Browse files- README.md +11 -0
- requirements.txt +0 -2
- src/main.py +9 -3
- src/routers/auth.py +8 -3
README.md
CHANGED
|
@@ -9,3 +9,14 @@ short_description: TaskFlow A Full-Stack-Web-Application Hackathon 2 Phase 2
|
|
| 9 |
---
|
| 10 |
|
| 11 |
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 9 |
---
|
| 10 |
|
| 11 |
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
| 12 |
+
|
| 13 |
+
## Cross-site deployment notes 🔧
|
| 14 |
+
|
| 15 |
+
If your backend is hosted on a different domain (e.g., Hugging Face Spaces) than your frontend (e.g., Vercel), follow these steps to make cookie-based auth work:
|
| 16 |
+
|
| 17 |
+
- Set `FRONTEND_URL` in your environment to your Vercel URL (e.g. `https://your-app.vercel.app`).
|
| 18 |
+
- Ensure `JWT_COOKIE_SECURE=True` in production (browsers require `Secure` when `SameSite=None`).
|
| 19 |
+
- Frontend fetch calls that rely on cookies must use `credentials: 'include'` (e.g. `fetch(url, { method, credentials: 'include' })`).
|
| 20 |
+
- Backend CORS must have `allow_credentials=True` and the exact frontend origin (not `*`) in allowed origins. This project reads `FRONTEND_URL` for that purpose.
|
| 21 |
+
|
| 22 |
+
If cookies are still not sent/received, open DevTools network tab and inspect the `Set-Cookie` response header and browser cookie/journal to see why it was blocked (e.g., SameSite/Secure/Domain issues).
|
requirements.txt
CHANGED
|
@@ -1,7 +1,5 @@
|
|
| 1 |
alembic>=1.17.2
|
| 2 |
fastapi>=0.124.4
|
| 3 |
-
passlib>=1.7.4
|
| 4 |
-
bcrypt>=4.0.0,<4.2.0
|
| 5 |
passlib[bcrypt]==1.7.4
|
| 6 |
bcrypt==4.2.1
|
| 7 |
psycopg2-binary>=2.9.11
|
|
|
|
| 1 |
alembic>=1.17.2
|
| 2 |
fastapi>=0.124.4
|
|
|
|
|
|
|
| 3 |
passlib[bcrypt]==1.7.4
|
| 4 |
bcrypt==4.2.1
|
| 5 |
psycopg2-binary>=2.9.11
|
src/main.py
CHANGED
|
@@ -21,14 +21,20 @@ app.include_router(tasks.router)
|
|
| 21 |
app.include_router(projects.router)
|
| 22 |
|
| 23 |
# CORS configuration (development and production)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 24 |
app.add_middleware(
|
| 25 |
CORSMiddleware,
|
| 26 |
-
allow_origins=
|
| 27 |
allow_credentials=True,
|
| 28 |
allow_methods=["*"],
|
| 29 |
allow_headers=["*"],
|
| 30 |
-
# Expose
|
| 31 |
-
expose_headers=["
|
| 32 |
)
|
| 33 |
|
| 34 |
@app.get("/api/health")
|
|
|
|
| 21 |
app.include_router(projects.router)
|
| 22 |
|
| 23 |
# CORS configuration (development and production)
|
| 24 |
+
# Use configured frontend origin (set your Vercel URL in FRONTEND_URL production env)
|
| 25 |
+
allow_origins = [settings.FRONTEND_URL]
|
| 26 |
+
# Always include localhost for local development/testing convenience
|
| 27 |
+
if "localhost" not in settings.FRONTEND_URL:
|
| 28 |
+
allow_origins.append("http://localhost:3000")
|
| 29 |
+
|
| 30 |
app.add_middleware(
|
| 31 |
CORSMiddleware,
|
| 32 |
+
allow_origins=list(dict.fromkeys(allow_origins)), # deduplicate if FRONTEND_URL is localhost
|
| 33 |
allow_credentials=True,
|
| 34 |
allow_methods=["*"],
|
| 35 |
allow_headers=["*"],
|
| 36 |
+
# Expose Set-Cookie so clients can inspect (browsers handle cookies automatically for credentials)
|
| 37 |
+
expose_headers=["Set-Cookie"]
|
| 38 |
)
|
| 39 |
|
| 40 |
@app.get("/api/health")
|
src/routers/auth.py
CHANGED
|
@@ -15,6 +15,12 @@ from ..config import settings
|
|
| 15 |
|
| 16 |
router = APIRouter(prefix="/api/auth", tags=["auth"])
|
| 17 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 18 |
|
| 19 |
@router.post("/register", response_model=RegisterResponse, status_code=status.HTTP_201_CREATED)
|
| 20 |
def register(user_data: RegisterRequest, response: Response, session: Session = Depends(get_session_dep)):
|
|
@@ -98,9 +104,8 @@ def login(login_data: LoginRequest, response: Response, session: Session = Depen
|
|
| 98 |
path="/"
|
| 99 |
)
|
| 100 |
|
| 101 |
-
# Debug: Print
|
| 102 |
-
print(f"
|
| 103 |
-
print(f"Cookie attributes: httponly={True}, secure={settings.JWT_COOKIE_SECURE}, samesite=none, max_age={settings.ACCESS_TOKEN_EXPIRE_DAYS * 24 * 60 * 60}")
|
| 104 |
|
| 105 |
# Return response
|
| 106 |
return LoginResponse(
|
|
|
|
| 15 |
|
| 16 |
router = APIRouter(prefix="/api/auth", tags=["auth"])
|
| 17 |
|
| 18 |
+
# NOTE: For cross-site cookie auth to work (backend on a different domain than the frontend):
|
| 19 |
+
# - The frontend must call login/register endpoints with `fetch(..., credentials: 'include')`
|
| 20 |
+
# - The backend must have CORS allow_credentials=True and the exact frontend origin in allow_origins
|
| 21 |
+
# - Cookies must be set with `Secure=True` and `samesite='none'` in production
|
| 22 |
+
# See project README or docs for full details
|
| 23 |
+
|
| 24 |
|
| 25 |
@router.post("/register", response_model=RegisterResponse, status_code=status.HTTP_201_CREATED)
|
| 26 |
def register(user_data: RegisterRequest, response: Response, session: Session = Depends(get_session_dep)):
|
|
|
|
| 104 |
path="/"
|
| 105 |
)
|
| 106 |
|
| 107 |
+
# Debug: Print cookie attributes (do NOT log token value in production)
|
| 108 |
+
print(f"Cookie set (httponly={True}, secure={settings.JWT_COOKIE_SECURE}, samesite=none, max_age={settings.ACCESS_TOKEN_EXPIRE_DAYS * 24 * 60 * 60})")
|
|
|
|
| 109 |
|
| 110 |
# Return response
|
| 111 |
return LoginResponse(
|