5

I am mounting a Flask app as a sub-application in my root FastAPI app, as explained in the documentation

Now I want to add an authentication layer using HTTPAuthorizationCredentials dependency, as nicely explained in this tutorial

tutorial code

How can I do that?

Preferably, I would like that any type of access attempt to my Flask sub-application goes first through a valid token authentication process implemented in my FastAPI root app. Is that possible?

Luiz Tauffer
  • 463
  • 6
  • 17

1 Answers1

1

You can use a custom WSGIMiddleware and authorize the call to flask app inside that like this:

from fastapi import FastAPI, Depends, HTTPException
from fastapi.middleware.wsgi import WSGIMiddleware
from flask import Flask, escape, request
from starlette.routing import Mount
from starlette.types import Scope, Receive, Send

flask_app = Flask(__name__)

def authenticate(authorization: str = Header()):
    # Add logic to authorize user
    if authorization == "VALID_TOKEN":
        return
    else:
        raise HTTPException(status_code=401, detail="Not Authorized")

class AuthWSGIMiddleware(WSGIMiddleware):

    async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
        _, authorization = next((header for header in scope['headers'] if header[0] == b'authorization'), (b'authorization', "" ))
        authenticate(authorization.decode('utf-8'))
        await super().__call__(scope, receive, send)

routes = [
            Mount("/v1", AuthWSGIMiddleware(flask_app)),
        ]

# OR Optionally use this as you were doing
# The above one is preferred as per starlette docs
# app.mount("/v1", WSGIMiddleware(flask_app))


@flask_app.route("/")
def flask_main():
    name = request.args.get("name", "World")
    return f"Hello, {escape(name)} from Flask!"

app = FastAPI(routes=routes, dependencies=[Depends(authenticate)])


@app.get("/v2")
def read_main():
    return {"message": "Hello World"}

For the tutorial you are looking at, you can replace the invoking authenticate function in my example inside AuthWSGIMiddleware->__call__() with

AuthHandler().decode_toke(authorization)

John S John
  • 292
  • 2
  • 9
  • 1
    Thanks @John, that works! I would also like to mention here a similar solution applied to static files: https://github.com/tiangolo/fastapi/issues/858#issuecomment-876564020 – Luiz Tauffer May 27 '22 at 09:18