I am making a simple login authentication app using React and Fastapi. My axios post request used to work intially just as indended with the exact same code except I changed the UI slightly.
Basically react would send a post request to my server and then it would repsond with a session token if it authenticates. This worked before. I dont know why it does not work anymore.
I tried just returning a simple {"token": "hello"} and then that was stored properly, so I am assuming it is something to do with the time it takes. Basically react does not wait for the POST request to send a response and moves on and returns the html. The logs show that fastapi is returning the correct thing. It goes inside the .then but then does not go into the function (response)
part of it.
react code for Login page
import { useNavigate } from "react-router";
import { fetchToken, setToken } from "./Auth";
import { useState } from "react";
import axios from "axios";
export default async function Login() {
const navigate = useNavigate();
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
//check to see if the fields are not empty
const login = () => {
console.log(email, password);
if ((email === "") & (password === "")) {
return;
} else {
axios
.post("http://localhost:8000/login", {
email: email,
password: password,
})
.then(function (response) {
console.log(response.data.token, "response.data.token");
if (response.data.token) {
setToken(response.data.token);
navigate("/profile");
}
})
.catch(function (error) {
console.log(error, "error");
});
}
};
return (
<div>
{fetchToken() ? (
<p>you are logged in</p>
) : (
<form>
<h3>Sign In</h3>
<div className="mb-3">
<label>Email address</label>
<input
type="email"
className="form-control"
placeholder="Enter email"
onChange={(e) => setEmail(e.target.value)}
/>
</div>
<div className="mb-3">
<label>Password</label>
<input
type="password"
className="form-control"
placeholder="Enter password"
onChange={(e) => setPassword(e.target.value)}
/>
</div>
<div className="d-grid">
<button type="submit" className="btn btn-primary" onClick={login}>
Submit
</button>
</div>
<p className="forgot-password text-right">
Not registered <a href="/sign-up">sign up?</a>
</p>
</form>
)}
</div>
);
}
backend FastAPI code
from fastapi import FastAPI
import jwt
from pydantic import BaseModel, Field
from fastapi.encoders import jsonable_encoder
from fastapi.middleware.cors import CORSMiddleware
from pymongo import MongoClient
from bson import ObjectId
import certifi
# imported for mongo maybe
from fastapi import FastAPI, Body, HTTPException, status
from fastapi.responses import Response, JSONResponse
SECERT_KEY = "YOUR_FAST_API_SECRET_KEY"
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRES_MINUTES = 800
test_user = {
"email": "temitope",
"password": "temipassword",
}
url = "uri"
app = FastAPI()
client = MongoClient(url, tlsCAFile=certifi.where())
db = client.test
origins = {
"http://localhost",
"http://localhost:3000",
}
app.add_middleware(
CORSMiddleware,
allow_origins = origins,
allow_credentials =True,
allow_methods = ["*"],
allow_headers= ["*"],
)
class LoginItem(BaseModel):
email: str
password: str
@app.get("/")
def read_root():
return {"Hello": "World"}
class Config:
schema_extra = {
"example": {
"email": "devang@hello",
"password": "encrypted"
}
}
class PyObjectId(ObjectId):
@classmethod
def __get_validators__(cls):
yield cls.validate
@classmethod
def validate(cls, v):
if not ObjectId.is_valid(v):
raise ValueError("Invalid objectid")
return ObjectId(v)
@classmethod
def __modify_schema__(cls, field_schema):
field_schema.update(type="string")
class UserModel(BaseModel):
id: PyObjectId = Field(default_factory=PyObjectId, alias="_id")
firstName: str = Field(...)
lastName: str = Field(...)
email: str = Field(...)
password: str = Field(...)
class Config:
allow_population_by_field_name = True
arbitrary_types_allowed = True
json_encoders = {ObjectId: str}
schema_extra = {
"example": {
"firstName": "Devang",
"lastName": "Agrawal",
"email": "devang@hello",
"password": "encrypted"
}
}
#function to encode the user
def get_jwt(user:UserModel):
#jsonify the user and delete the firstName and lastName and _id
data = jsonable_encoder(user)
print(data)
del data['firstName']
del data['lastName']
del data['_id']
print(data)
return jwt.encode(data, SECERT_KEY, algorithm=ALGORITHM)
#function to retrieve user with the given encoded jwt token
def get_user(encoded_jwt):
#look at all the users in the database
users = db["users"].find()
#check if the user exists in the database
for user in users:
if user['encoded_jwt'] == encoded_jwt:
return user
@app.post("/login")
async def user_login(loginitem:LoginItem):
#look at all the users in the database
data = jsonable_encoder(loginitem)
# return {"token": data["email"]}
print(f"{data} is the data")
#encode the user
encoded_jwt = jwt.encode(data, SECERT_KEY, algorithm=ALGORITHM)
#check if the user exists in the database
if get_user(encoded_jwt) != None:
print("success")
return {"token": encoded_jwt}
print("failed")
return {"message": "login failed"}
@app.post("/add", response_description="Add new user", response_model=UserModel)
async def create_user(user: UserModel = Body(...)):
#jsonify the userx
user = jsonable_encoder(user)
#encode the user and add it to the user object
user['encoded_jwt'] = get_jwt(user)
del user['password']
print(user)
#add the user to the database
new_user = db["users"].insert_one(user)
created_user = db["users"].find_one({"_id": new_user.inserted_id})
#return success message
return JSONResponse(status_code=status.HTTP_201_CREATED, content=created_user)
Does someone know how to make sure that the response is processed properly with axios post. Also I tried async and await, while setting random timeouts but nothing worked.
CodePudding user response:
Try to move the login
function in the onSubmit
event of the form
:
<form onSubmit={login}>
Remove the onClick
from the submit
button:
<button type="submit" className="btn btn-primary">...</button>
And call e.preventDefault()
before the execution:
const login = (e) => {
e.preventDefault();
console.log(email, password);
if ((email === '') & (password === '')) {
return;
}
axios
.post('http://localhost:8000/login', { email, password })
.then(function (response) {
console.log(response.data.token, 'response.data.token');
if (response.data.token) {
setToken(response.data.token);
navigate('/profile');
}
})
.catch(function (error) {
console.log(error, 'error');
});
}
};