fix(dropbox): fix Invalid redirect_uri error by adding PUBLIC_BASE_URL config and URL-encoding

- Add PUBLIC_BASE_URL optional config to override auto-detected OAuth redirect URIs
  when behind a reverse proxy that doesn't forward X-Forwarded-Proto headers
- Add _build_dropbox_redirect_uri() helper in app/api/dropbox.py
- URL-encode redirect_uri in server-side Dropbox authorization URL
- Add _get_dropbox_callback_url() helper in app/views/dropbox.py
- Pass callback_url to both setup and callback templates
- Update templates to use server-provided callback_url instead of window.location.origin
- Update settings_service.py to register new setting
- Update .env.demo, ConfigurationGuide.md, and DropboxSetup.md documentation
- Add tests for new helper functions and global-authorize-url endpoint

Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot]
2026-03-20 08:19:48 +00:00
parent f2ba74a483
commit 5e3e2b1999
11 changed files with 230 additions and 6 deletions
+18
View File
@@ -14,6 +14,19 @@ from app.views.base import APIRouter, Depends, get_db, require_login, settings,
router = APIRouter()
def _get_dropbox_callback_url(request: Request) -> str:
"""Return the Dropbox OAuth callback URL.
Uses ``PUBLIC_BASE_URL`` when configured so that the redirect URI displayed
to the user (and registered in the Dropbox developer console) matches the
one used in the OAuth authorization request. Falls back to deriving the URL
from the incoming request when ``PUBLIC_BASE_URL`` is not set.
"""
if settings.public_base_url:
return settings.public_base_url.rstrip("/") + "/dropbox-callback"
return f"{request.url.scheme}://{request.url.netloc}/dropbox-callback"
@router.get("/dropbox-setup")
@require_login
async def dropbox_setup_page(
@@ -30,6 +43,8 @@ async def dropbox_setup_page(
path from the integration's existing config is pre-populated; global
admin credentials are never exposed in this mode.
"""
callback_url = _get_dropbox_callback_url(request)
if integration_id is not None:
owner_id = get_current_owner_id(request)
integration = (
@@ -67,6 +82,7 @@ async def dropbox_setup_page(
"app_secret_value": "",
"refresh_token_value": "",
"global_creds_available": global_creds_available,
"callback_url": callback_url,
},
)
@@ -86,6 +102,7 @@ async def dropbox_setup_page(
"integration_id": integration_id,
"integration_name": None,
"integration_type": None,
"callback_url": callback_url,
},
)
@@ -116,5 +133,6 @@ async def dropbox_callback(request: Request, code: str = None, error: str = None
"app_key_value": "", # The callback will prioritize sessionStorage values
"app_secret_value": "", # The callback will prioritize sessionStorage values
"folder_path": "", # The callback will prioritize sessionStorage values
"callback_url": _get_dropbox_callback_url(request),
},
)