Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

fastapi - optional OAuth2 authentication

Tags:

python

fastapi

I need to create a API with a route that is able to recognize if the current user is the one indicated in the request or not (also no auth should be valid)

For the others paths I followed https://fastapi.tiangolo.com/tutorial/security/oauth2-jwt/ and everything work with Bearer with JWT tokens like this

user: User = Depends(get_current_active_user)

Modifying the methods provided by the docs I tried with

oauth2_scheme = OAuth2PasswordBearer(tokenUrl="auth")

async def get_user_or_none(db: Session = Depends(get_db), token: str = Depends(oauth2_scheme)):
    """
    Return the current active user if is present (using the token Bearer) or None
    """
    try:
        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
        username: str = payload.get("sub")
        if username is None:
            return None
    except JWTError:
        return None
    
    # check user in db
    user = crud.get_user(db, username)
    if user is None:
        return None
    return user

@router.get("/api/{user_id}/structure")
async def get_user_structure(
    user_id: int,
    user = Depends(get_user_or_none),
    db: Session = Depends(get_db)
):
    # do_something() if user.id == user_id else do_something_else()

but I receive an error

401 Error: Unauthorized {
    "detail": "Not authenticated"
}
like image 550
dorezzz Avatar asked May 10 '26 09:05

dorezzz


1 Answers

You need to use a different OAuth2PasswordBearer for these optionally authenticated endpoints with auto_error=False, e.g.

optional_oauth2_scheme = OAuth2PasswordBearer(tokenUrl="auth", auto_error=False)

async def get_user_or_none(db: Session = Depends(get_db), token: str | None = Depends(optional_oauth2_scheme)):
    ...

Now the token will be None when the Authorization header isn't provided, resulting in your desired behavior.

like image 161
avi Avatar answered May 12 '26 22:05

avi