API responses with 422 on login request
Question:
I want to login a user via a form and a API request. But I allways get a 422 Error, and I can’t locate the faulty code.
The API is written with FastAPI in python.
This is the Swagger API documentation.
When I try to login via Swagger it works and I get a 200.
FastAPI written in Python
@router.post("/login", status_code=status.HTTP_200_OK, response_model=Token)
async def login_for_access_token(form_data: OAuth2PasswordRequestForm = Depends(),
db: Session = Depends(get_db)):
user = authenticate_user(form_data.username, form_data.password, db)
if not user:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Incorrect username or password",
headers={"WWW-Authenticate": "Bearer"},
)
access_token_expires = timedelta(minutes=60)
access_token = create_access_token(
data={"sub": user.username}, expires_delta=access_token_expires
)
check_password_expiration(user)
if user.change_password:
return {"access_token": access_token,
"token_type": "bearer",
"message": "Password expired, please set new password"}
return {"access_token": access_token, "token_type": "bearer"}
Javascript API Request
function loginRequest(username_value, password_value) {
var data = new FormData();
data.append("username", username_value);
data.append("password", password_value);
for (var pair of data.entries()) {
console.log(pair[0] + ', ' + pair[1]);
}
fetch("https://www.example-url.net", {
method: "POST",
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: data
})
.then(response => {
console.log(response.json())
})
}
With that request, I get a 422 Error.
If I take a look into the console I get the body
At which Point is the server not able to process the request body? Why are the values not correctly processed?
PS: I know that I get a jwt in return and I’m not processing that one yet. But in the first step I would like to make a successfull API Call.
Answers:
With Swagger the data is probably uri-encoded for you. But with js fetch and application/x-www-form-urlencoded, this is not the case. Since your password contains an asterisk (*), you might want to uri-encode it first, using:
encodeURIComponent(password_value)
before sending the data to the server.
I prefer you to use multipart/form-data
then application/x-www-form-urlencoded
format. As using multipart/form-data
request content-type you can send FormData
object directly and on server it will read as a form-data and you are good to go. But If you want to pass form-data in application/x-www-form-urlencoded
you need to pass it using URLSearchParams
. You can try this:
const data = new URLSearchParams(new FormData(formElement));
The problem was outside my code I posted. There was something blocking the payload between server and api domain/ssl redirection. I still don’t know what exactly, but the space of possible solutions is outside the problem I posted here.
I want to login a user via a form and a API request. But I allways get a 422 Error, and I can’t locate the faulty code.
The API is written with FastAPI in python.
This is the Swagger API documentation.
When I try to login via Swagger it works and I get a 200.
FastAPI written in Python
@router.post("/login", status_code=status.HTTP_200_OK, response_model=Token)
async def login_for_access_token(form_data: OAuth2PasswordRequestForm = Depends(),
db: Session = Depends(get_db)):
user = authenticate_user(form_data.username, form_data.password, db)
if not user:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Incorrect username or password",
headers={"WWW-Authenticate": "Bearer"},
)
access_token_expires = timedelta(minutes=60)
access_token = create_access_token(
data={"sub": user.username}, expires_delta=access_token_expires
)
check_password_expiration(user)
if user.change_password:
return {"access_token": access_token,
"token_type": "bearer",
"message": "Password expired, please set new password"}
return {"access_token": access_token, "token_type": "bearer"}
Javascript API Request
function loginRequest(username_value, password_value) {
var data = new FormData();
data.append("username", username_value);
data.append("password", password_value);
for (var pair of data.entries()) {
console.log(pair[0] + ', ' + pair[1]);
}
fetch("https://www.example-url.net", {
method: "POST",
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: data
})
.then(response => {
console.log(response.json())
})
}
With that request, I get a 422 Error.
If I take a look into the console I get the body
At which Point is the server not able to process the request body? Why are the values not correctly processed?
PS: I know that I get a jwt in return and I’m not processing that one yet. But in the first step I would like to make a successfull API Call.
With Swagger the data is probably uri-encoded for you. But with js fetch and application/x-www-form-urlencoded, this is not the case. Since your password contains an asterisk (*), you might want to uri-encode it first, using:
encodeURIComponent(password_value)
before sending the data to the server.
I prefer you to use multipart/form-data
then application/x-www-form-urlencoded
format. As using multipart/form-data
request content-type you can send FormData
object directly and on server it will read as a form-data and you are good to go. But If you want to pass form-data in application/x-www-form-urlencoded
you need to pass it using URLSearchParams
. You can try this:
const data = new URLSearchParams(new FormData(formElement));
The problem was outside my code I posted. There was something blocking the payload between server and api domain/ssl redirection. I still don’t know what exactly, but the space of possible solutions is outside the problem I posted here.