Securing FastAPI’s Swagger(doc) and redoc Endpoints with Password Protection

Ray
2 min readAug 21, 2023

--

In FastAPI, the automatic generation of API documentation using Swagger UI (available at /docs) and ReDoc (available at /redoc) is one of the most appreciated features. However, sometimes we want to restrict access to these pages, for instance, to prevent unwanted users from accessing our API's documentation. In this blog post, we will walk through the steps to add password protection to the doc and redoc endpoints in FastAPI.

Step 1: Create a Dependency

First, we need to create a dependency function that will handle the authentication process. In this example, we will use basic authentication, which requires the user to enter a username and password.

def get_current_username(credentials: HTTPBasicCredentials = Depends(security)) -> str:
correct_username = secrets.compare_digest(credentials.username, "username")
correct_password = secrets.compare_digest(credentials.password, "password")
if not (correct_username and correct_password):
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Incorrect email or password",
headers={"WWW-Authenticate": "Basic"},
)
return credentials.username

Step 2: Secure the doc and redoc Endpoints

Next, we need to secure the doc and redoc endpoints using the dependency function created in step 1.

@api_router.get("/docs", response_class=HTMLResponse)
async def get_docs(username: str = Depends(get_current_username)) -> HTMLResponse:
return get_swagger_ui_html(openapi_url="/api/openapi.json", title="docs")


@api_router.get("/redoc", response_class=HTMLResponse)
async def get_redoc(username: str = Depends(get_current_username)) -> HTMLResponse:
return get_redoc_html(openapi_url="/api/openapi.json", title="redoc")

In this example, the get_docs and get_redoc endpoints are secured with the get_current_username dependency. When a user tries to access these endpoints, they will be prompted to enter a username and password. If the credentials match the ones specified in the dependency function, the user will be granted access to the documentation pages.

Step 3: Disable Default doc and redoc URLs (Optional)

To secure the doc and redoc endpoints, it is necessary to disable the default endpoints provided by FastAPI. We do this by setting the docs_url and redoc_url parameters to None when initializing the FastAPI app.

app = FastAPI(
title="FastAPI",
version=metadata.version("FastAPI"),
docs_url=None,
redoc_url=None,
openapi_url="/api/openapi.json",
default_response_class=UJSONResponse,
)

Conclusion

With just a few lines of code, you can add password protection to your FastAPI application’s documentation pages. This simple authentication method helps restrict access to your API documentation and keep it secure. Remember to choose a strong username and password and consider using more advanced authentication methods, like OAuth or token-based authentication, for increased security in production environments.

Additional content

In the comments, it was reported that there may be a security issue with the above code. The problem is that /api/openapi.json is exposed.

the problem is that /api/openapi.json is exposed.

FaskAPI -> openapi_url -> None

app = FastAPI(
title="robert",
version=metadata.version("robert"),
docs_url=None,
redoc_url=None,
openapi_url=None,
default_response_class=UJSONResponse,
)

Add a route code to authenticate when accessing /api/openapi.json.

@api_router.get("/openapi.json", response_class=JSONResponse)
async def get_openapi_json(current_user: str = Depends(get_current_username)) -> JSONResponse:
from fastapi.openapi.utils import get_openapi
from robert.web.application import get_app
openapi_schema = get_openapi(
title="SERVICE TITLE",
version="1.0.0",
description="API documentation",
routes=get_app().routes,
)
return JSONResponse(openapi_schema)

If you proceed as above, the openapi.json will not be exposed directly.

--

--

Responses (2)