Fastapi How to restrict token creation to defined users

Question:

I have a dictionary of users with (username, password) as key, value pair.
i would like to restrict the authorisation creation to only users in my dictionary.
So any other user who is not in the dictionary shouldn’t be able to create a token.

I try this but it’s not working, I can still create token to a new user.

    @api.post("/token")
async def get_token(form_data: OAuth2PasswordRequestForm = Depends()):
    if not authenticate_user(username=form_data.username,
                             password=form_data.password):
        raise HTTPException(status_code=403, detail='Authentication failed')
    else:
        return {
            "access_token": form_data.username,
            "token_type": "bearer"
        }

    raise HTTPException(status_code=403,
                        detail='Authentication failed')
Asked By: aba2s

||

Answers:

You never compare anything against form_data.username – the only thing you do is that you start looping over the user, and you check whether the first users password match – well, the user’s password. This will always be true.

Instead, retrieve the user you’re looking for and compare the password if present:

@api.post("/token")
async def get_token(form_data: OAuth2PasswordRequestForm = Depends()):
    user = users.get(form_data.username)

    if user and authenticate_user(form_data=username, password=form_data.password):
        return {
            "access_token": form_data.username,
            "token_type": "bearer"
        }

    raise HTTPException(status_code=403,
                        detail='Authentication failed')

I’d also like to point out that you’re using the users username as the token. This means that anyone can fake a token by simply supplying the username they want to be authenticated as.

Instead, use secrets.token_urlsafe() to generate a token that can be used as an authentication secret. You’ll need to store these tokens somewhere, but in this example it seems like you’re storing everything in the currently running Python application for users, so you can do the same for tokens. Define valid_tokens = {} somewhere when initializing your application, then insert rows into this dict to assign a username.

token = secrets.token_urlsafe(32)
valid_tokens[token] = form_data.user_name

return {
    "access_token": token,
    "token_type": "bearer"
}

You can then verify this token in a separate function and use it to look up the username of the logged in user from the token.

Answered By: MatsLindh
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.