FastApi 422 Unprocessable Entity, on authentication, how to fix?

Question:

Cannot understand even if i delete all inside function and just print something still got this error, but when i use fastapi docs, and try signing with that, it work.

@auth_router.post('/signin')
async def sign_in(username: str = Form(...), password: str = Form(...)) -> dict:
    user = await authenticate_user(username, password)

    if not user:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED, 
            detail='Invalid username or password',
        )

    user_obj = await User_Pydantic.from_tortoise_orm(user)
    user_token = await generate_token(user_obj)

    return {
        'access_token': user_token,
        'token_type': 'bearer',
    }

Before i use OAuth2PasswordRequestForm, when got 422 error, try another way.

my model is tortoise orm, and when need i convert it to pydantic model,
in docs all is work.

JS

handleEvent(signinform, 'submit', e => {
    e.preventDefault();
    if(!isEmpty(signinform)){

        signInUsername = getElement('input[name="username"]', signinform).value;
        signInPassword = getElement('input[name="password"]', signinform).value;
        recaptchaV3 = getElement('[name="g-recaptcha-response"]').value;

        if(recaptchaV3){
            signInData = new FormData();
            signInData.append('username', signInUsername);
            signInData.append('password', signInPassword);

            isLogened = request('POST', '/signin', signInData);
            if(isLogened){
                log(isLogened);
            }
            
        } else{
            alert('Reload Page');
        }

    }

})

authenticate_user func

async def authenticate_user(username: str, password: str):
    user = await User.get(username=username)

    if not user or not user.verify_password(password):
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED, 
            detail='Invalid username or password',
        )
    return user

My request function

const request = (method, url, data = null) => {
    return new Promise((resolve, reject) => {
        let xhr = new XMLHttpRequest()
        xhr.open(method, url, true)
        xhr.setRequestHeader('Content-Type', 'application/json')
        xhr.onerror = function () {
            console.log(xhr.response);
        };
        xhr.onload = () => {
        if (xhr.status === 200) {
            return resolve(JSON.parse(xhr.responseText || '{}'))
            } else {
                return reject(new Error(`Request failed with status ${xhr.status}`))
            }
        } 
        if (data) {
            xhr.send(JSON.stringify(data))
        } else {
            xhr.send()
        }


    })
}
Asked By: WhyIsThatHappening

||

Answers:

Although you did not publish the error, who’s purpose is to tell you the problem, I’m fairly sure the problem lies in the way you perform the request.

The line

xhr.setRequestHeader('Content-Type', 'application/json')

means that you are sending json data, which is not accepted by the authentication form of openapi. Also, you are stringifying the data into json which, again, is not an accepted format.

Thus, changing the content type to www-form-urlencoded and adding a FormData object to your request’s body, will make it work.

You can see it in the github discussions below

https://github.com/tiangolo/fastapi/issues/2740
https://github.com/tiangolo/fastapi/issues/1431

Answered By: lsabi

Ensure that you have provided content type in your request,

xhr.setRequestHeader('Content-Type', 'application/json')

If it’s there then verify the format of your input. Here, you have declared two varibales – signInUsername and signInPassword.

Important: You might provided a default value for these files in FastAPI. In that case, if you provided an empty content or null as the attribute values then the fastapi will throw the above error.

Ensure that the data that you are sending to the server is correct.

Answered By: Codemaker
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.