Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

How does async __call__ work in HTTPBearer and where is it invoked? #13336

Answered by YuriiMotov
SDAravind asked this question in Questions
Discussion options

First Check

  • I added a very descriptive title here.
  • I used the GitHub search to find a similar question 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.

Commit to Help

  • I commit to help with one of those options 👆

Example Code

from typing import Annotated

from fastapi import Depends
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer

class ValidateHTTPBearer(HTTPBearer):
    async def validate_parse_token(self, token: str):
        ...

    async def validate_current_user(self, parsed_token: dict):
        ...

    async def __call__(self, request: Request):
        ...
        parsed_token = await self.validate_parse_token("token")
        await self.validate_current_user(parsed_token)
        ...

WhoAreYou = Depends(ValidateHTTPBearer())
CurrentUser = Annotated[HTTPAuthorizationCredentials, WhoAreYou]

Description

I have seen HTTPBearer class in fastapi and it uses Async call method and then use dependency injection. I have created a sub-class using HTTPBearer having additional validation logic at dependency level.

Do we invoke in call that inherits async class like await super().__call__()?

  1. Now I want to understand how is Async call being invoked and from where it is awaited?

  2. Feature Request: Can we pass optional additional validation logic in HTTPBearer as parameter? If yes, pass custom class or list of methods that would

  • validate token
  • validate current user

If token is valid check then validate user
If user exists in the db return that current user
Otherwise throw 403

Operating System

Linux

Operating System Details

Fedora 41

FastAPI Version

0.115.7

Pydantic Version

2.10

Python Version

3.12

Additional Context

No response

You must be logged in to vote

So, as I understand, this is what you needed:

from collections.abc import Awaitable, Callable
from typing import Annotated, Optional

from fastapi import Depends, FastAPI, HTTPException, Request
from fastapi.security import HTTPBearer

class ValidateHTTPBearer(HTTPBearer):
    def __init__(
        self,
        *,
        scheme_name: Optional[str] = None,
        other_validations: list[Callable[[str], Awaitable[None]]],
    ):
        super().__init__(scheme_name=scheme_name)
        self._other_validations = other_validations

    async def validate_parse_token(self, token: str) -> dict:
        data = token.split(":")
        return {"user": data[0], "something": data[1]}

    async def

Replies: 1 comment · 2 replies

Comment options

The answer for the first question: FastAPI analyzes parameters of the endpoint function and executes ValidateHTTPBearer (this will create an instance of that class as if you call ValidateHTTPBearer()).

I think it's a mistake in WhoAreYou = Depends(ValidateHTTPBearer) and you actually need this: WhoAreYou = Depends(ValidateHTTPBearer()). In this case FastAPI will call __call__ method of the instance of class ValidateHTTPBearer.

Regarding your second question - I didn't get it. Could you clarify?

Do you want to achieve something like this?

from typing import Annotated

from fastapi import Depends, FastAPI, Request
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer

class ValidateHTTPBearer(HTTPBearer):
    def __init__(self, validate_token: str):
        super().__init__()
        self._validate_token = validate_token

    async def validate_parse_token(self, token: str):
        ...

    async def validate_current_user(self, parsed_token: dict):
        ...

    async def __call__(self, request: Request):

        print(f"{self._validate_token=}") # You can use `self._validate_token` here
        ...
        parsed_token = await self.validate_parse_token("token")
        await self.validate_current_user(parsed_token)
        ...

WhoAreYou = Depends(ValidateHTTPBearer(validate_token="123"))
CurrentUser = Annotated[HTTPAuthorizationCredentials, WhoAreYou]

app = FastAPI()

@app.get("/")
def index(current_use: CurrentUser):
    pass


You must be logged in to vote
2 replies
@SDAravind
Comment options

My Bad. It should have been WhoAreYou = Depends(ValidateHTTPBearer()). It's updated now.

If I need to create similar functionality using parent and sub-class. where should I invoke parent async __call__ method in sub-class. Where is the await keyword used to trigger a co-routine?

Regarding the second question. I need to write custom class which inherits HTTPBearer and write custom validation. Instead if HTTPBearer accepts another optional parameter say validate_methods which accepts list of functions like validate token, validate user run like a validation chain and return output of last validated method. It would be nice to have feature.

Currently, HTTPBearer accepts four parameters bearerFormat, scheme_name, description and auto-error. It currently check if authorisation code is present or not. If I have JWT token, I would like to validate and parse the JWT token. Then, use the parsed token and validate the user in the database and return the validated user.

HTTPBearer(schema_name="SomeBearer", other_validations=[validate_token(), validate_user()])
@YuriiMotov
Comment options

So, as I understand, this is what you needed:

from collections.abc import Awaitable, Callable
from typing import Annotated, Optional

from fastapi import Depends, FastAPI, HTTPException, Request
from fastapi.security import HTTPBearer

class ValidateHTTPBearer(HTTPBearer):
    def __init__(
        self,
        *,
        scheme_name: Optional[str] = None,
        other_validations: list[Callable[[str], Awaitable[None]]],
    ):
        super().__init__(scheme_name=scheme_name)
        self._other_validations = other_validations

    async def validate_parse_token(self, token: str) -> dict:
        data = token.split(":")
        return {"user": data[0], "something": data[1]}

    async def validate_current_user(self, parsed_token: dict) -> str:
        return parsed_token["user"]

    async def __call__(self, request: Request) -> str:
        # Call the parent class to get the credentials
        auth_credentials = await super().__call__(request)

        # Validate the token and user
        parsed_token = await self.validate_parse_token(auth_credentials.credentials)
        user = await self.validate_current_user(parsed_token)

        # Perform other validations
        token_data = parsed_token.copy()
        token_data["user"] = user
        for validation in self._other_validations:
            await validation(token_data)

        return user


async def validate_token(token_data: dict):
    if token_data["something"] != "123":
        raise HTTPException(status_code=401, detail="Invalid token")

async def validate_user(token_data: dict):
    if token_data.get("user") != "admin":
        raise HTTPException(status_code=403, detail="Invalid user")

security = ValidateHTTPBearer(
    scheme_name="SomeBearer",
    other_validations=[validate_token, validate_user]
)

CurrentUser = Annotated[str, Depends(security)]

app = FastAPI()

@app.get("/")
def index(current_user: CurrentUser):
    return {"user": current_user}

And the answer to your question:

Now I want to understand how is Async call being invoked and from where it is awaited?

FastAPI analyzes dependencies of the endpoint and calls\awaits them depending on the function signature.
Once you pass the instance of ValidateHTTPBearer as a dependency, it looks at the signature of __call__ method and awaits it

Answer selected by YuriiMotov
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Question or problem
2 participants
Morty Proxy This is a proxified and sanitized view of the page, visit original site.