Home

Blog

How to Protect Your FastAPI OpenAPI/Swagger Docs with Authentication

9 min read
FastAPI Swagger and OpenAPI documentation protected by authentication, showing a browser window with shield and padlock icons
By David Muraya • October 25, 2025

FastAPI's interactive documentation, available at /docs and /redoc, is one of its best features. It provides a live, explorable interface for your API, making development and testing much easier. But in a production environment, leaving this documentation publicly accessible can be a security risk. It gives anyone a detailed map of your API's structure, including all endpoints, parameters, and data models.

This guide will show you how to protect your API documentation so that only authenticated users can access it. We'll disable the default public docs and then create our own protected endpoints to serve them securely.

This article assumes you have already implemented token-based authentication. If you haven't, you can learn how in my guide to authentication in FastAPI with JWT.

The Goal

Our goal is simple:

  1. Disable the public /docs, /redoc, and /openapi.json endpoints.
  2. Create new endpoints, for example at /api/docs and /openapi.json, that require a valid authentication token to be accessed.

Step 1: Disable the Default Documentation

First, we need to turn off the default, public documentation routes. You can do this by setting docs_url, redoc_url, and openapi_url to None when you initialize your FastAPI application.

# main.py
from fastapi import FastAPI

app = FastAPI(
    title="My Secure API",
    docs_url=None,
    redoc_url=None,
    openapi_url=None,
)

With this change, visiting /docs or /redoc will now result in a "Not Found" error. Your API schema will no longer be publicly exposed.

Step 2: Create Protected Documentation Endpoints

Now, we'll create our own endpoints to serve the documentation, but we'll protect them with an authentication dependency. This dependency will ensure that only users who provide a valid token can access these routes.

Let's create a new router for this purpose.

# in a file like docs_router.py
from fastapi import APIRouter, Depends, HTTPException, status
from fastapi.openapi.docs import get_swagger_ui_html
from fastapi.openapi.utils import get_openapi

# This is a placeholder for your actual authentication logic.
# It should verify the token in the cookies and return the user object.
from .auth import get_current_active_user

router = APIRouter()

@router.get("/openapi.json", include_in_schema=False)
async def get_open_api_endpoint(current_user: dict = Depends(get_current_active_user)):
    """
    Serves the OpenAPI schema, but only to authenticated users.
    """
    if not current_user:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="You are not authorized to view the API documentation.",
        )
    return get_openapi(
        title=app.title,
        version=app.version,
        description=app.description,
        routes=app.routes,
    )

@router.get("/docs", include_in_schema=False)
async def get_documentation(current_user: dict = Depends(get_current_active_user)):
    """
    Serves the Swagger UI, but only to authenticated users.
    """
    if not current_user:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="You are not authorized to view the API documentation.",
        )
    return get_swagger_ui_html(
        openapi_url="/openapi.json",
        title=app.title + " - Swagger UI",
    )

Here’s what this code does:

  • We create two new routes: /openapi.json and /docs.
  • Both routes depend on get_current_active_user. This is our authentication dependency. FastAPI will run this function first for any request to these endpoints.
  • If get_current_active_user successfully validates the user's token, it returns the user, and the request proceeds.
  • If the user is not authenticated, the dependency will raise an HTTPException, and FastAPI will return a 401 Unauthorized error.
  • The get_openapi and get_swagger_ui_html functions are the same ones FastAPI uses internally to generate the schema and the UI.

Step 3: Include the New Router

Finally, include the new router in your main application file.

# main.py
from fastapi import FastAPI
from .docs_router import router as docs_router

app = FastAPI(
    title="My Secure API",
    docs_url=None,
    redoc_url=None,
    openapi_url=None,
)

# Include the protected documentation router
app.include_router(docs_router)

@app.get("/")
def read_root():
    return {"Hello": "World"}

Now, your documentation is secure. Unauthenticated users will be denied access, while authenticated users can visit /docs to view the interactive API documentation.

FAQ

1. Why not just use HTTP Basic Auth to protect the docs? You could, but it's less secure and less flexible. HTTP Basic Auth is not ideal for modern APIs. Token-based authentication using standards like OAuth2 and JWT is preferred because it allows for features like token expiration, refresh tokens, and granular permissions (scopes), which Basic Auth does not support.

2. Can I show different parts of the API documentation to different user roles? Yes. You can generate a different OpenAPI schema based on the user's role. In your custom /openapi.json endpoint, you could inspect the current_user object to determine their role (e.g., 'admin' vs. 'user'). Then, you can filter the app.routes list before passing it to get_openapi, effectively creating a custom schema for that user role.

3. What if my API is purely for internal use? Do I still need to protect the docs? It is always a good practice. Even for internal APIs, accidentally exposing documentation can leak information about your system's architecture. Protecting it by default is a strong security posture that helps prevent accidental information disclosure.

4. Is it necessary to protect both /docs and /openapi.json? Yes. The /docs endpoint is just an HTML page that renders the schema from /openapi.json. If you only protect /docs, an attacker could still access /openapi.json directly and get your full API schema. You must protect the source of the data (/openapi.json) as well as the UI that displays it.

Share This Article

About the Author

David Muraya is a Solutions Architect specializing in Python, FastAPI, and Cloud Infrastructure. He is passionate about building scalable, production-ready applications and sharing his knowledge with the developer community. You can connect with him on LinkedIn.

Related Blog Posts

Enjoyed this blog post? Check out these related posts!

A Guide to Authentication in FastAPI with JWT

A Guide to Authentication in FastAPI with JWT

From Basic Auth to OAuth2 with Password Flow and JWT Tokens.

Read More...

Adding Google Authentication to Your FastAPI Application

Adding Google Authentication to Your FastAPI Application

A guide to adding Google Authentication to your FastAPI app.

Read More...

A Practical Guide to FastAPI Security

A Practical Guide to FastAPI Security

A Comprehensive Checklist for Production-Ready Security for a FastAPI Application

Read More...

How to Handle File Uploads in FastAPI

How to Handle File Uploads in FastAPI

A Practical Guide to Streaming and Validating File Uploads

Read More...

On this page

The GoalStep 1: Disable the Default DocumentationStep 2: Create Protected Documentation EndpointsStep 3: Include the New RouterFAQ

Back to Blogs

Contact Me

Have a project in mind? Send me an email at hello@davidmuraya.com and let's bring your ideas to life. I am always available for exciting discussions.

© 2025 David Muraya. All rights reserved.