-
Basic Question Does FastAPI provide a method for implementing authentication middleware or similar on the docs themselves (e.g. to protect access to Additional context My company is currently relying on a needlessly-complex Django backend, whose main purpose is serving an API via the Django REST framework. However, it feels like half the bugs the frontend app folks are running into are caused by a disconnect between what the Django app is doing and the API documentation wiki (which is maintained by hand; it's a monster). FastAPI thus looks like a perfect alternative. However, it's a requirement for us that the API documentation only be accessible to specific authenticated users. It looks like I could easily disable the docs when run in a production environment (as opposed to a local testing environment), but if it's possible to serve the docs on production but explicitly protect them that would be ideal (the API in part facilitates interaction between frontend apps and IOT devices, so the interactive portions of the docs would be a lot easier to use and maintain on specific hosted servers; setting up working local environments is complicated). In my ideal world, I'd love to also auto-populate the initial authentication credentials for the interactive queries with the current user's authentication token (to allow no-configuration usage of them immediately upon access). I wasn't able to find anything in the FastAPI docs about meddling with the way the documentation is handled, but if I missed it I'd love a link! |
Beta Was this translation helpful? Give feedback.
Replies: 18 comments 5 replies
-
You can look in the docs, there's a list of articles, one of them by niels
does that, will edit if you can't find it
Le mer. 3 juil. 2019 à 8:18 AM, ianbeck <[email protected]> a écrit :
… *Basic Question*
Does FastAPI provide a method for implementing authentication middleware
or similar on the docs themselves (e.g. to protect access to /docs and
/redoc)?
*Additional context*
My company is currently relying on a needlessly-complex Django backend,
whose main purpose is serving an API via the Django REST framework.
However, it feels like half the bugs the frontend app folks are running
into are caused by a disconnect between what the Django app is doing and
the API documentation wiki (which is maintained by hand; it's a monster).
FastAPI thus looks like a perfect alternative. However, it's a requirement
for us that the API documentation only be accessible to specific
authenticated users. It looks like I could easily disable the docs when run
in a production environment (as opposed to a local testing environment),
but if it's possible to serve the docs on production but explicitly protect
them that would be ideal (the API in part facilitates interaction between
frontend apps and IOT devices, so the interactive portions of the docs
would be a lot easier to use and maintain on specific hosted servers;
setting up working local environments is complicated).
In my ideal world, I'd love to also auto-populate the initial
authentication credentials for the interactive queries with the current
user's authentication token (to allow no-configuration usage of them
immediately upon access). I wasn't able to find anything in the FastAPI
docs about meddling with the way the documentation is handled, but if I
missed it I'd love a link!
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
<#364>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AAINSPS7OVVHVUODRHMOAPTP5RABXANCNFSM4H5CISYQ>
.
|
Beta Was this translation helpful? Give feedback.
-
Thank you, that was exactly what I was looking for! |
Beta Was this translation helpful? Give feedback.
-
Thanks @euri10 for your help here! 🍰 🚀 Thanks @ianbeck for reporting back and closing the issue. 🎉 |
Beta Was this translation helpful? Give feedback.
-
Put Traefik in front of it. |
Beta Was this translation helpful? Give feedback.
-
Medium put the article behind a paywall. Is there another source for that information? |
Beta Was this translation helpful? Give feedback.
-
The solution discussed in the article is to disabled the automatic generated endpoints and create your own with authentication |
Beta Was this translation helpful? Give feedback.
-
I do not think it is good policy to give links to sources where you have to pay?! :( |
Beta Was this translation helpful? Give feedback.
-
use traefik forward auth
…On Thu, Feb 18, 2021 at 3:57 AM Paweł Graczyk ***@***.***> wrote:
https://medium.com/data-rebels/fastapi-how-to-add-basic-and-cookie-authentication-a45c85ef47d3
I do not think it is good policy to for giving link to sources where you
have to pay?! :(
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#364 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/ABFW7DYVVTLTX2UV7GXY4IDS7TI7VANCNFSM4H5CISYQ>
.
|
Beta Was this translation helpful? Give feedback.
-
Hi there, I just find an easy solution to this question. You can simply disable default /docs and create docs behind authentication Example code:
|
Beta Was this translation helpful? Give feedback.
-
Pro tipsUsing ReDoc Hiding those endpoints A small improvement for code mantainance return get_openapi(title=app.title, version=app.version, routes=app.routes) instead of return get_openapi(title = "FastAPI", version="0.1.0", routes=app.routes) This way, every-time you change the version (or if you need to change the title in the future), you can do it where you would normally do it and you won't have to remember where is that defined. Save time for the future you. Final code from fastapi import FastAPI
from fastapi.openapi.docs import get_redoc_html, get_swagger_ui_html
from fastapi.openapi.utils import get_openapi
import secrets
from fastapi import Depends, FastAPI, HTTPException, status
from fastapi.security import HTTPBasic, HTTPBasicCredentials
app = FastAPI(
title="FastAPI",
version="0.1.0",
docs_url=None,
redoc_url=None,
openapi_url = None,
)
security = HTTPBasic()
def get_current_username(credentials: HTTPBasicCredentials = Depends(security)):
correct_username = secrets.compare_digest(credentials.username, "user")
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
@app.get("/docs", include_in_schema=False)
async def get_swagger_documentation(username: str = Depends(get_current_username)):
return get_swagger_ui_html(openapi_url="/openapi.json", title="docs")
@app.get("/redoc", include_in_schema=False)
async def get_redoc_documentation(username: str = Depends(get_current_username)):
return get_redoc_html(openapi_url="/openapi.json", title="docs")
@app.get("/openapi.json", include_in_schema=False)
async def openapi(username: str = Depends(get_current_username)):
return get_openapi(title=app.title, version=app.version, routes=app.routes Final words: Just remember this is an example and you still need to connect this small authentication code to your real login system or, at least, use environment variables. If you are protecting your API documentation, just don't hard code your credentials... |
Beta Was this translation helpful? Give feedback.
-
Any hint if I want to only require basic auth for prod but not for development? |
Beta Was this translation helpful? Give feedback.
-
This did not work for me. The doc page still opens up. And I can still test out the endpoints. I do see an Authorize button on the right now. Not sure if that was the intended outcome. |
Beta Was this translation helpful? Give feedback.
-
Just delete your cookies & local storage or use incognito |
Beta Was this translation helpful? Give feedback.
-
Hi there, how can I do this for versioned documentation. I am using fastapi-versioning |
Beta Was this translation helpful? Give feedback.
-
For anyone who wants to enable HTTP basic authentication modal, here is a workaround: Assuming the environment is set to 'prod', follow these steps:
import base64
import secrets
from starlette.middleware.base import BaseHTTPMiddleware, RequestResponseEndpoint
from starlette.requests import Request
from starlette.responses import Response
class ApidocBasicAuthMiddleware(BaseHTTPMiddleware):
async def dispatch( # type: ignore
self, request: Request, call_next: RequestResponseEndpoint):
if request.url.path in ['/docs', '/redoc', '/openapi.json']:
auth_header = request.headers.get('Authorization')
if auth_header:
try:
scheme, credentials = auth_header.split()
if scheme.lower() == 'basic':
decoded = base64.b64decode(credentials).decode('ascii')
username, password = decoded.split(':')
correct_username = secrets.compare_digest(
username, 'your-username')
correct_password = secrets.compare_digest(
password, 'your-password')
if correct_username and correct_password:
return await call_next(request)
except:
pass
response = Response(content='Unauthorized', status_code=401)
response.headers['WWW-Authenticate'] = 'Basic'
return response
return await call_next(request)
app = FastAPI()
if app_env == 'production':
@app.get(
'/docs',
tags=['documentation'],
include_in_schema=False,
)
async def get_swagger_documentation() -> HTMLResponse:
return get_swagger_ui_html(openapi_url='/openapi.json', title='docs')
@app.get(
'/openapi.json',
tags=['documentation'],
include_in_schema=False,
)
async def openapi() -> Dict[str, Any]:
return get_openapi(title='FastAPI', version='0.1.0', routes=app.routes)
@app.get(
'/redoc',
tags=['documentation'],
include_in_schema=False,
)
async def get_redoc() -> Dict[str, Any]:
return get_redoc_html(openapi_url="/openapi.json", title="docs")
app.add_middleware(ApidocBasicAuthMiddleware) then the authentication modal shows up correctly |
Beta Was this translation helpful? Give feedback.
-
Any hints if it might be possible to use something simple like Basic Auth for protecting the /docs as first stage and then have the endpoints protected via a JWT token? Preferably it should be possible to use the nice OAuth2/OpenID mechanisms within Swagger to create and refresh the token. |
Beta Was this translation helpful? Give feedback.
Hi there, I just find an easy solution to this question.
You can simply disable default /docs and create docs behind authentication
Example code: