To implement authentication for a FastAPI endpoint, I want to make use of the Depends functionality offered in the latest versions (>=0.95) of FastAPI. I have tried several ways to implement it but I am facing an error "AttributeError: 'property' object has no attribute 'get'". This implies that the starlette Request object is not recognised as such when using Depends.
Endpoint implementation:
@app.get("/")
async def home(user: Annotated[User, Depends(authenticate_request(Request))]):
"""
status _summary_
Returns status message if service is running
"""
if isinstance(user, User):
return {"Welcome, service is running ok!"}
raise HTTPException(
status_code=401,
detail="User not authorized!",
)
Function authenticate_request checks validity of cookies based on provided Request:
def authenticate_request(request: Request) -> User:
cookie1 = request.cookies.get("x")
cookie2 = request.cookies.get("y")
if cookie1 is not None and cookie2 is not None:
tenant = get_tenant(request)
if user := authenticate_cookies(cookie1, cookie2, tenant):
if not tenant.startswith(user.tenant):
print("Unauthorized: Token hostname mismatch")
raise Exception("Token hostname mismatch")
return user
print("Unauthorized: please login")
raise HTTPException(status_code=401, detail="Unauthorized: please login")
This results in error "AttributeError: 'property' object has no attribute 'get'". This implies that the Request object is not passed correctly or is not recognised as such.
I then tried to solve this without using Depends:
@app.get("/")
async def home(request: Request):
"""
status _summary_
Returns status message if service is running
"""
user = authenticate_request(request=request)
if isinstance(user, User):
return {"Welcome, service is running ok!"}
raise HTTPException(
status_code=401,
detail="User not authorized!",
)
This is working correctly. If no valid cookie is provided a 401 is returned. Based on this I come to the conclusion that my authenticate_request() function is working correctly.
Does anybody know why there is a difference in behaviour between Depends() and the alternative solution?
Help is much appreciated!
Regards, Laurens
When using
Depends(), you just pass the name of the dependency function within the brackets (i.e., don't call it directly, just pass it as a parameter toDepends()). As described in the documentation:Thus, any other parameters that your dependency function takes, you simply need to declare them in that function and not passing them through
Depends(). Same applies to theRequestobject. FastAPI will analyze the parameters for the dependency, and process them in the same way as the parameters for a path operation function (also known as endpoint), including sub-dependencies.Hence, your endpoint should look like this:
and your
authenticate_requestdependency function should be as follows:Additional Information
Instead of a "callable" function, one could also use a Python class instead as a dependency, as Python classes are also callable.
One not only can they use a "callable" dependency class, but also a "callable" instance of that dependency class, which would allow them to initially pass fixed content when creating the instance of the class, as well as pass additional parameters and sub-dependencies when the endpoint is called.
The
__init__method in the example below is used to declare the parameters of the instance that we can use to "parameterize" the dependency (the fixed content). FastAPI won't ever touch or care about__init__, it is used directly in the code when creating the instance of the class.The
__call__method, on the other hand, is what FastAPI will use to check for additional parameters and sub-dependencies, and this is what will be called to pass a value to the parameter in your endpoint, when it will later be called.Hence, in the example below,
fixed_contentis the attribute used to "parameterize" the dependency, whileqis the additional query parameter to pass a value for, when a client is calling the endpoint.Example