Box redirect URI: infer from hostname when X-Forwarded-Host is absent
The previous fix relied on Apache forwarding X-Forwarded-Host, but on optical-dev that header isn't set. Apache uses ProxyPreserveHost (so request.host correctly resolves to optical-dev.oliver.solutions) but the backend connection is plain http and Flask sees no path prefix, so the fallback emitted "http://optical-dev.oliver.solutions/auth/box/callback" — which Box rejected as "insecure_redirect_uri" (no HTTPS) and which is also missing the required /ai_qc/ prefix. Resolution order is now: 1. BOX_REDIRECT_URI env var (escape hatch / unusual deploys). 2. X-Forwarded-Host header if Apache happens to send it. 3. Otherwise: infer from request.host. Any host that isn't localhost or 127.0.0.1 is treated as the optical-dev / optical-prod proxy and gets HTTPS + the /ai_qc/ prefix. localhost stays http and rootless. Verified all five paths (dev with and without XF-Host, laptop on localhost and 127.0.0.1, explicit override) produce the right URL. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
7c3945417a
commit
f17a4ed6da
1 changed files with 16 additions and 7 deletions
|
|
@ -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'])
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue