Search code examples
pythonoauth-2.0fastapi

FastAPI grant_type refresh token


I'm new to OAth2 and using FastApi, working great until now stumped on how to detect grant_type refresh. Here from the form, i'm getting grant_type as "password" or "refresh_token". The problem is that when I pass grant_type "refresh_token" the code doesn't even get to the condidtional. Is it due to the OAuth2PasswordRequestForm not allowing it?

from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm

@app.post("/token", response_model=Token) 
async def login_for_access_token(form_data: OAuth2PasswordRequestForm = Depends()):
    user = authenticate_user(fake_users_db, form_data.username, form_data.password)
    
    #for login grant_type = password
    #for refreshToken grant_type = refresh_token
    grant_type_str = str(form_data.grant_type)
    print('167', str(form_data.grant_type))
    try:
        user.username
    except:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail=user['detail'],
            headers={"WWW-Authenticate": "Bearer"},
        )
    try:
        form_data.grant_type
    except:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="must specifiy grant type",
            headers={"WWW-Authenticate": "Bearer"},
        )
    if grant_type_str.startswith('password'):
        access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
        access_token = create_access_token(data={"sub": user.username}, expires_delta=access_token_expires)
        return {"access_token": access_token, "expires_in": ACCESS_TOKEN_EXPIRE_MINUTES,
            "token_type": "bearer", "scope": "read write groups", "grant_type": "password"}
    elif grant_type_str.startswith('refresh_token'):
        access_token_expires_refresh = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES_REFRESH)
        access_token = create_refresh_token(
            data={"sub": user.username}, expires_delta=access_token_expires_refresh
        )
        return {"access_token": access_token, "expires_in": ACCESS_TOKEN_EXPIRE_MINUTES_REFRESH,
            "token_type": "bearer", "scope": "read write groups", "grant_type": "refresh_token"}

Running the above, the code doenst even get to my elif "refresh_token". Instead I get '''422 Unprocessable Entity'''.


Solution

  • This the OAuth2PasswordRequestForm declaration (fastapi.security.oauth2.py):

    class OAuth2PasswordRequestForm:
      """
      This is a dependency class, use it like:
      ...
    
      It creates the following Form request parameters in your endpoint:
    
      grant_type: the OAuth2 spec says it is required and MUST be the fixed string "password".
      Nevertheless, this dependency class is permissive and allows not passing it. If you want to enforce it,
      use instead the OAuth2PasswordRequestFormStrict dependency.
    

    You can't pass a value other than 'password'. https://fastapi.tiangolo.com/tutorial/security/simple-oauth2/?h=grant_type#code-to-get-the-username-and-password