From 1143ec376faec4ca45fea199af72448525028c53 Mon Sep 17 00:00:00 2001 From: Artur Shiriev Date: Fri, 6 Nov 2026 12:22:46 +0300 Subject: [PATCH] Preserve OAuth settings in offline FastAPI Swagger docs Refs #437 --- lite_bootstrap/helpers/fastapi_helpers.py | 7 ++++- tests/test_fastapi_offline_docs.py | 34 ++++++++++++++++++++++- 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/lite_bootstrap/helpers/fastapi_helpers.py b/lite_bootstrap/helpers/fastapi_helpers.py index 120f4dd..6af2d9d 100644 --- a/lite_bootstrap/helpers/fastapi_helpers.py +++ b/lite_bootstrap/helpers/fastapi_helpers.py @@ -64,10 +64,15 @@ def enable_offline_docs( @app.get(docs_url, include_in_schema=False) async def custom_swagger_ui_html(request: Request) -> HTMLResponse: root_path = _safe_root_path(request.scope.get("root_path", "")) + oauth2_redirect_url = app.swagger_ui_oauth2_redirect_url + if oauth2_redirect_url: + oauth2_redirect_url = f"{root_path}{oauth2_redirect_url}" return get_swagger_ui_html( openapi_url=f"{root_path}{app_openapi_url}", title=f"{app.title} - Swagger UI", - oauth2_redirect_url=app.swagger_ui_oauth2_redirect_url, + oauth2_redirect_url=oauth2_redirect_url, + init_oauth=app.swagger_ui_init_oauth, + swagger_ui_parameters=app.swagger_ui_parameters, swagger_js_url=f"{root_path}{static_path}/swagger-ui-bundle.js", swagger_css_url=f"{root_path}{static_path}/swagger-ui.css", ) diff --git a/tests/test_fastapi_offline_docs.py b/tests/test_fastapi_offline_docs.py index 4711ed2..88202f8 100644 --- a/tests/test_fastapi_offline_docs.py +++ b/tests/test_fastapi_offline_docs.py @@ -30,7 +30,12 @@ def test_fastapi_offline_docs() -> None: def test_fastapi_offline_docs_root_path() -> None: - app: FastAPI = FastAPI(title="Tests", root_path="/some-root-path", docs_url="/custom_docs") + app = FastAPI( + title="Tests", + root_path="/some-root-path", + docs_url="/custom_docs", + swagger_ui_oauth2_redirect_url=None, + ) enable_offline_docs(app, static_path="/static") with TestClient(app, root_path="/some-root-path") as client: @@ -38,6 +43,7 @@ def test_fastapi_offline_docs_root_path() -> None: assert response.status_code == HTTPStatus.OK assert "/some-root-path/static/swagger-ui.css" in response.text assert "/some-root-path/static/swagger-ui-bundle.js" in response.text + assert "oauth2RedirectUrl" not in response.text response = client.get("/some-root-path/static/swagger-ui.css") assert response.status_code == HTTPStatus.OK @@ -48,6 +54,32 @@ def test_fastapi_offline_docs_root_path() -> None: assert "/some-root-path/openapi.json" in response.text +@pytest.mark.parametrize( + "swagger_setting", + [ + '"clientId": "public-demo"', + '"usePkceWithAuthorizationCodeGrant": true', + '"persistAuthorization": true', + "oauth2RedirectUrl: window.location.origin + '/api/docs/oauth2-redirect'", + ], +) +def test_offline_swagger_preserves_native_settings(swagger_setting: str) -> None: + app = FastAPI( + swagger_ui_init_oauth={"clientId": "public-demo", "usePkceWithAuthorizationCodeGrant": True}, + swagger_ui_parameters={"persistAuthorization": True}, + ) + with TestClient(app, root_path="/api") as client: + native_response = client.get("/docs") + + enable_offline_docs(app, static_path="/static") + with TestClient(app, root_path="/api") as client: + offline_response = client.get("/docs") + + assert native_response.status_code == offline_response.status_code == HTTPStatus.OK + assert swagger_setting in native_response.text + assert swagger_setting in offline_response.text + + def test_fastapi_offline_docs_raises_without_openapi_url() -> None: app = FastAPI(openapi_url=None)