pythonwebfastapiweb-frameworkspyjwt

Authenticated and None Authenticated Verification Path


So using fastapi PyJWT which works well, I'm struggling to making this work

user_dep = Annotated[Dict,Depends(api.get_current_user)]
@app.get('/')
async def home(request: Request,user:user_dep=Optional[models.AuthorizedUser]):
    print(user)
    if user is not None:
        return RedirectResponse(url='/dashboard/')
    return templates.TemplateResponse('home.html',context={'request':request})

Intended functionality: If the user was already logged it, they will automatically get redirected to the intended page I want

Running this exact piece of code and when I guess the / path, it returns 401 Unauthorized which is not what I currently what for this one.

async def get_current_user(token: Annotated[str,Depends(oauth2_bearer)]):
       try:
              payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
              username: str = payload.get('username')
              user_id: int = payload.get('id')
              rank: str = payload.get('rank')
              division: str = payload.get('division')
              if username is None or user_id is None:
                     return None
                     #raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Could not validate user")
              return {'username': username, 'id': user_id, 'rank': rank, 'division':division}
       except PyJWTError:
              return None
              #raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Could not validate credentials")

Is there a possibility I am missing some steps, or anything?

I've tried everything, even sometimes, removing doing this:

`=

@app.get('/')
async def home(request: Request,user:user_dep=None):
    print(user)
    if user is not None:
        return RedirectResponse(url='/dashboard/')
    return templates.TemplateResponse('home.html',context={'request':request})```

```py
@app.get('/')
async def home(request: Request):
        user = await user_dep()
    print(user)
    if user is not None:
        return RedirectResponse(url='/dashboard/')
    return templates.TemplateResponse('home.html',context={'request':request})

Nothing seems to work


Solution

  • OAuth2PasswordBearer will (by default) generate a 401 error when an Authorization header is not present, so your dependency code never actually runs (so you can't return None).

    To change the behavior you can supply the parameter auto_error when creating your OAuth2PasswordBearer instance.

    By default, if no HTTP Auhtorization header is provided, required for OAuth2 authentication, it will automatically cancel the request and send the client an error.

    If auto_error is set to False, when the HTTP Authorization header is not available, instead of erroring out, the dependency result will be None.

    This is useful when you want to have optional authentication.

    It is also useful when you want to have authentication that can be provided in one of multiple optional ways (for example, with OAuth2 or in a cookie).

    You then check if token is None before attempting to decode it in your authentication function.

    However, be aware that this will also make all other endpoints available if no token is present, just without user information. A solution to this is to define two get_current_user functions, one get_current_user and one get_optional_user, which in turn either can depend on two differently configured instances of OAuth2PasswordBearer, or you can handle the None case for the token in your get_current_user function and raise a 401 if the token isn't present yourself.