Skip to content

Add support to lazy initialize OAuth2 classes #3317

@michaeloliverx

Description

@michaeloliverx

First check

  • I added a very descriptive title to this issue.
  • I used the GitHub search to find a similar issue and didn't find it.
  • I searched the FastAPI documentation, with the integrated search.
  • I already searched in Google "How to X in FastAPI" and didn't find any information.
  • I already read and followed all the tutorial in the docs and didn't find an answer.
  • I already checked if it is not related to FastAPI but to Pydantic.
  • I already checked if it is not related to FastAPI but to Swagger UI.
  • I already checked if it is not related to FastAPI but to ReDoc.
  • After submitting this, I commit to:
    • Read open issues with questions until I find 2 issues where I can help someone and add a comment to help there.
    • Or, I already hit the "watch" button in this repository to receive notifications and I commit to help at least 2 people that ask questions in the future.
    • Implement a Pull Request for a confirmed bug.

Example

Here's a self-contained minimal, reproducible, example with my use case:

from fastapi import FastAPI, Security
from fastapi.security import OAuth2AuthorizationCodeBearer
from pydantic import BaseSettings


class Config(BaseSettings):
    OAUTH2_AUTHORIZATION_URL: str = "https://example.com/authorize"
    OAUTH2_TOKEN_URL: str = "https://example.com/oauth/token"


config = Config()
app = FastAPI()


oauth2_scheme = OAuth2AuthorizationCodeBearer(
    authorizationUrl=config.OAUTH2_AUTHORIZATION_URL,
    tokenUrl=config.OAUTH2_TOKEN_URL,
)


@app.get("/private-route", dependencies=[Security(oauth2_scheme, scopes=["admin"])])
async def private_route():
    pass

Description

  • Config is instantiated at import time because OAuth2AuthorizationCodeBearer class needs values from it
  • I would like a way to lazy initialize OAuth2AuthorizationCodeBearer and other security classes

The solution you would like

Since Kludex/uvicorn#875 we have been able to use --factory option with uvicorn. This is known as the application factory pattern and is widely used in Flask. I would like to delay configuring the OAuth2AuthorizationCodeBearer until inside the create_app method like below:

from typing import Optional

from fastapi import APIRouter, FastAPI, Security
from fastapi.security import OAuth2AuthorizationCodeBearer
from pydantic import BaseSettings


class Config(BaseSettings):
    OAUTH2_AUTHORIZATION_URL: str = "https://example.com/authorize"
    OAUTH2_TOKEN_URL: str = "https://example.com/oauth/token"


oauth2_scheme = OAuth2AuthorizationCodeBearer()

router = APIRouter()


@router.get("/private-route", dependencies=[Security(oauth2_scheme, scopes=["admin"])])
async def private_route():
    pass


def create_app(config: Optional[Config] = None) -> FastAPI:
    config = config or Config()
    app = FastAPI()
    app.include_router(router)

    # I want to configure here instead
    oauth2_scheme.initialize(
        authorizationUrl=config.OAUTH2_AUTHORIZATION_URL,
        tokenUrl=config.OAUTH2_TOKEN_URL,
    )
    return app

Describe alternatives you've considered

Subclassing OAuth2AuthorizationCodeBearer to add the functionality, but I think this is a common use case it could be officially supported or a note in the docs.

Environment

  • OS: [e.g. Linux / Windows / macOS]: macOS
  • FastAPI Version [e.g. 0.3.0]: 0.65.1
  • Python Version: 3.9.4

Additional context

If this is agreed I can do the implementation and open a PR.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions