From 43f05c97278d38b3cf427940cfb241903a2efb05 Mon Sep 17 00:00:00 2001 From: Yusufa09 Date: Sat, 1 Aug 2026 01:49:21 -0400 Subject: [PATCH] Build OAuth redirect_uri from PUBLIC_BASE_URL instead of request headers --- flask-server/.env.example | 6 ++++++ flask-server/api/oauth_blueprint.py | 16 ++++++++++++---- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/flask-server/.env.example b/flask-server/.env.example index dbeff52..efca2c5 100644 --- a/flask-server/.env.example +++ b/flask-server/.env.example @@ -69,6 +69,12 @@ CANCERVERSE_LOWRES_PATH=/home/visitor/cancerverse_lowres # Defaults to http://localhost:5173 for dev. # FRONTEND_URL=https://bodymaps.wse.jhu.edu +# The app's public origin, used to build the OAuth redirect_uri that providers +# match as an exact string. REQUIRED in production: derived from the request it +# would depend on the proxy chain reporting the scheme correctly, and an +# http:// value makes every sign-in fail. Leave unset in dev. +# PUBLIC_BASE_URL=https://bodymaps.wse.jhu.edu + # --- OAuth providers (optional) --- # Leave unset to disable a provider; its button stays disabled in the UI and # /api/auth/oauth/providers reports it as unavailable. diff --git a/flask-server/api/oauth_blueprint.py b/flask-server/api/oauth_blueprint.py index c0a8612..09662e5 100644 --- a/flask-server/api/oauth_blueprint.py +++ b/flask-server/api/oauth_blueprint.py @@ -34,6 +34,17 @@ def _frontend_url() -> str: return os.environ.get("FRONTEND_URL", "http://localhost:5173") +# The provider matches redirect_uri as an exact string, so it has to be the +# app's real public origin. Deriving it from the request means trusting the +# proxy chain to report scheme/host correctly, which isn't always in our +# control — an nginx that rewrites X-Forwarded-Proto yields http:// and every +# sign-in fails. Set PUBLIC_BASE_URL in production to state it outright; +# unset, we fall back to the request (correct for local dev). +def _callback_url(provider: str) -> str: + base = os.environ.get("PUBLIC_BASE_URL") or request.url_root + return urljoin(base.rstrip("/") + "/", f"api/auth/oauth/{provider}/callback") + + def _provider_configured(provider: str) -> bool: return bool( os.environ.get(f"{provider.upper()}_CLIENT_ID") @@ -89,10 +100,7 @@ def oauth_start(provider): return jsonify({"error": f"{provider} sign-in isn't configured"}), 503 client = oauth.create_client(provider) - # Build the absolute callback URL from this request so it matches whatever - # host/port the app is actually served on. - redirect_uri = urljoin(request.url_root, f"api/auth/oauth/{provider}/callback") - return client.authorize_redirect(redirect_uri) + return client.authorize_redirect(_callback_url(provider)) @oauth_blueprint.route("/auth/oauth//callback", methods=["GET"])