Seth commited on
Commit
168b3d6
·
1 Parent(s): e6a3185
Files changed (3) hide show
  1. Dockerfile +2 -1
  2. SETUP.md +3 -1
  3. backend/app/auth_routes.py +40 -5
Dockerfile CHANGED
@@ -29,4 +29,5 @@ EXPOSE 7860
29
  # Set PYTHONPATH to include backend directory
30
  ENV PYTHONPATH=/app/backend:$PYTHONPATH
31
 
32
- CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "7860", "--app-dir", "/app/backend"]
 
 
29
  # Set PYTHONPATH to include backend directory
30
  ENV PYTHONPATH=/app/backend:$PYTHONPATH
31
 
32
+ # --proxy-headers: X-Forwarded-Proto/Host from Hugging Face edge so OAuth redirect_uri is https://
33
+ CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "7860", "--app-dir", "/app/backend", "--proxy-headers"]
SETUP.md CHANGED
@@ -61,7 +61,9 @@
61
  export SESSION_SECRET=$(openssl rand -hex 32)
62
  ```
63
 
64
- For HTTPS deployments (e.g. Hugging Face Spaces), also set `HTTPS_ONLY_COOKIES=1` and add your public origin to `CORS_ORIGINS` if the browser origin differs from the API host.
 
 
65
 
66
  3. **Run Backend**:
67
  ```bash
 
61
  export SESSION_SECRET=$(openssl rand -hex 32)
62
  ```
63
 
64
+ For **Hugging Face Spaces**, set `FRONTEND_ORIGIN` to **`https://`**, e.g. `https://your-space.hf.space` (not `http://`). Google’s OAuth policy rejects `http://` redirect URIs for public hosts; the **Authorized redirect URI** in Google Cloud must be the **https** callback, e.g. `https://your-space.hf.space/api/auth/google/callback`.
65
+
66
+ For HTTPS deployments, also set `HTTPS_ONLY_COOKIES=1` and add your public origin to `CORS_ORIGINS` if the browser origin differs from the API host.
67
 
68
  3. **Run Backend**:
69
  ```bash
backend/app/auth_routes.py CHANGED
@@ -25,22 +25,57 @@ def _client_configured() -> bool:
25
  return bool(os.environ.get("GOOGLE_CLIENT_ID", "").strip() and os.environ.get("GOOGLE_CLIENT_SECRET", "").strip())
26
 
27
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
  def _redirect_uri(request: Request) -> str:
29
  """Callback URL; must match an entry in Google Cloud Console → OAuth client."""
30
  explicit = os.environ.get("GOOGLE_REDIRECT_URI", "").strip()
31
  if explicit:
32
- return explicit
33
  fe = os.environ.get("FRONTEND_ORIGIN", "").strip()
34
  if fe:
35
- return fe.rstrip("/") + "/api/auth/google/callback"
36
- return str(request.base_url).rstrip("/") + "/api/auth/google/callback"
37
 
38
 
39
  def _post_login_url(request: Request) -> str:
40
  fe = os.environ.get("FRONTEND_ORIGIN", "").strip()
41
  if fe:
42
- return fe.rstrip("/") + "/"
43
- return str(request.base_url).rstrip("/") + "/"
44
 
45
 
46
  @router.get("/status")
 
25
  return bool(os.environ.get("GOOGLE_CLIENT_ID", "").strip() and os.environ.get("GOOGLE_CLIENT_SECRET", "").strip())
26
 
27
 
28
+ def _normalize_https_public_origin(origin: str) -> str:
29
+ """Spaces like Hugging Face are always HTTPS; fix http:// saved by mistake or bad defaults."""
30
+ o = origin.strip().rstrip("/")
31
+ if o.startswith("http://") and ".hf.space" in o:
32
+ return "https://" + o[7:]
33
+ return o
34
+
35
+
36
+ def _public_request_base(request: Request) -> str:
37
+ """
38
+ Browser-facing origin (scheme + host, no path). Uses proxy headers so OAuth redirect_uri
39
+ is https://... behind Hugging Face / nginx (request.base_url alone is often http:// internally).
40
+ """
41
+ fwd_proto = request.headers.get("x-forwarded-proto")
42
+ if fwd_proto:
43
+ proto = fwd_proto.split(",")[0].strip().lower()
44
+ else:
45
+ proto = (request.url.scheme or "http").lower()
46
+
47
+ fwd_host = request.headers.get("x-forwarded-host")
48
+ if fwd_host:
49
+ host = fwd_host.split(",")[0].strip()
50
+ else:
51
+ host = request.headers.get("host") or request.url.netloc or ""
52
+
53
+ if host:
54
+ # Use Host / X-Forwarded-Host as-is (keeps localhost:5173 for dev proxy).
55
+ base = f"{proto}://{host}" if proto else f"https://{host}"
56
+ base = _normalize_https_public_origin(base)
57
+ return base.rstrip("/")
58
+
59
+ base = str(request.base_url).rstrip("/")
60
+ return _normalize_https_public_origin(base)
61
+
62
+
63
  def _redirect_uri(request: Request) -> str:
64
  """Callback URL; must match an entry in Google Cloud Console → OAuth client."""
65
  explicit = os.environ.get("GOOGLE_REDIRECT_URI", "").strip()
66
  if explicit:
67
+ return _normalize_https_public_origin(explicit)
68
  fe = os.environ.get("FRONTEND_ORIGIN", "").strip()
69
  if fe:
70
+ return _normalize_https_public_origin(fe) + "/api/auth/google/callback"
71
+ return _public_request_base(request) + "/api/auth/google/callback"
72
 
73
 
74
  def _post_login_url(request: Request) -> str:
75
  fe = os.environ.get("FRONTEND_ORIGIN", "").strip()
76
  if fe:
77
+ return _normalize_https_public_origin(fe) + "/"
78
+ return _public_request_base(request) + "/"
79
 
80
 
81
  @router.get("/status")