diff --git a/backend/api_server.py b/backend/api_server.py index 08735a9..459fd3e 100755 --- a/backend/api_server.py +++ b/backend/api_server.py @@ -5385,22 +5385,31 @@ def _box_redirect_uri(): """ Compute the public OAuth callback URL. - - BOX_REDIRECT_URI env var wins if set (override / testing). - - Otherwise, when behind the Apache reverse proxy on optical-dev/optical-prod, - X-Forwarded-Host is set; the app is mounted at /ai_qc/ so we prepend it. - - Direct access (Nick's laptop, port 7183) goes through neither — use the - Flask host as-is. + Resolution order: + 1. BOX_REDIRECT_URI env var if set (escape hatch / unusual deploys). + 2. X-Forwarded-Host header if Apache sets it (some setups do). + 3. Otherwise, infer from request.host: anything that isn't localhost + is treated as being behind the Apache proxy at /ai_qc/ over HTTPS + (this matches optical-dev / optical-prod where Apache uses + ProxyPreserveHost so request.host is already the public hostname, + but the backend connection is plain http and Flask sees no prefix). """ explicit = (os.environ.get('BOX_REDIRECT_URI') or '').strip() if explicit: return explicit + forwarded_host = request.headers.get('X-Forwarded-Host') if forwarded_host: - # First entry if a chain of proxies was somehow involved. host = forwarded_host.split(',')[0].strip() proto = request.headers.get('X-Forwarded-Proto', 'https') return f'{proto}://{host}/ai_qc/auth/box/callback' - return f'{request.scheme}://{request.host}/auth/box/callback' + + host = (request.host or '').strip() + is_local = (not host) or 'localhost' in host or host.startswith('127.0.0.1') + if not is_local: + # Behind the optical-dev / optical-prod Apache proxy, mounted at /ai_qc/. + return f'https://{host}/ai_qc/auth/box/callback' + return f'{request.scheme}://{host}/auth/box/callback' @app.route('/auth/box/login', methods=['GET'])