Securing FastAPI’s Swagger(doc) and redoc Endpoints with Password Protection
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.