I am developing a booking app and trying to implement the authentication so when I send POST request from the Postman I get the user information but when send the POST request from react application using axios library then I get 404 Not Found error
This is AuthContext page for different events in login
import { createContext, useEffect, useReducer } from "react";
const INITIAL_STATE = {
user: JSON.parse(localStorage.getItem("user")) || null,
loading: false,
error: null,
};
export const AuthContext = createContext(INITIAL_STATE);
const AuthReducer = (state, action) => {
switch (action.type) {
case "LOGIN_START":
return {
user: null,
loading: true,
error: null,
};
case "LOGIN_SUCCESS":
return {
user: action.payload,
loading: false,
error: null,
};
case "LOGIN_FAILURE":
return {
user: null,
loading: false,
error: action.payload,
};
case "LOGOUT":
return {
user: null,
loading: false,
error: null,
};
default:
return state;
}
};
export const AuthContextProvider = ({ children }) => {
const [state, dispatch] = useReducer(AuthReducer, INITIAL_STATE);
useEffect(() => {
localStorage.setItem("user", JSON.stringify(state.user));
}, [state.user]);
return (
<AuthContext.Provider
value={{
user: state.user,
loading: state.loading,
error: state.error,
dispatch,
}}
>
{children}
</AuthContext.Provider>
);
};
This is the Login page code
import axios from "axios";
import { useContext, useState } from "react";
import { AuthContext } from "../../context/AuthContext";
import { useNavigate } from "react-router-dom";
import "./login.css";
const Login = () => {
const [credentials, setCredentials] = useState({
username: undefined,
password: undefined,
});
const {user, loading, error, dispatch } = useContext(AuthContext);
const navigate = useNavigate();
const handleChange = (e) => {
setCredentials((prev) => ({ ...prev, [e.target.id]: e.target.value }));
};
const handleClick = async (e) => {
e.preventDefault();
dispatch({ type: "LOGIN_START" });
try {
const res = await axios.post("/auth/login", credentials);
dispatch({ type: "LOGIN_SUCCESS", payload: res.data });
navigate("/");
} catch (err) {
dispatch({ type: "LOGIN_FAILURE", payload: err.response.data });
}
};
return (
<div className="login">
<div className="lContainer">
<input
type="text"
placeholder="username"
id="username"
onChange={handleChange}
className="lInput"
/>
<input
type="password"
placeholder="password"
id="password"
onChange={handleChange}
className="lInput"
/>
<button disabled={loading} onClick={handleClick} className="lButton">
Login
</button>
{error && <span>{error.message}</span>}
</div>
</div>
);
};
export default Login;
I connected the frontend with express server using proxy
"proxy": "http://localhost:8800/api"
This is package.json file
{
"name": "hotel-moment",
"version": "0.1.0",
"private": true,
"dependencies": {
"@fortawesome/fontawesome-svg-core": "^6.2.1",
"@fortawesome/free-regular-svg-icons": "^6.2.1",
"@fortawesome/free-solid-svg-icons": "^6.2.1",
"@fortawesome/react-fontawesome": "^0.2.0",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"axios": "^1.2.4",
"date-fns": "^2.29.3",
"http-proxy-middleware": "^2.0.6",
"react": "^18.2.0",
"react-date-range": "^1.4.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.4.4",
"react-scripts": "5.0.1",
"web-vitals": "^2.1.4"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"proxy": "http://localhost:8800/api"
}
These are the controllers for the login route
import User from "../models/User.js";
import bcrypt from "bcrypt";
import { createError } from "../utils/error.js";
import jwt from "jsonwebtoken";
// Sign Up user function
export const register = async (req, res, next) => {
try {
const salt = bcrypt.genSaltSync(10);
const hash = bcrypt.hashSync(req.body.password, salt);
const newUser = new User({
username: req.body.username,
email: req.body.email,
password: hash,
});
await newUser.save();
res.status(200).send("User has been created");
} catch(err) {
next(err);
}
}
// Login user function
export const login = async (req, res, next) => {
try {
const user = await User.findOne({username: req.body.username});
if(!user) return next(createError(404, "User not found"));
const isPasswordCorrect = await bcrypt.compare(req.body.password, user.password);
const token = jwt.sign({ id:user._id, isAdmin: user.isAdmin }, process.env.JWT_TOKEN);
if(!isPasswordCorrect) return next(createError(400, "Incorrct password or username"));
const {password, isAdmin, ...otherDetails} = user._doc;
res
.cookie("access_token", token, {
httpOnly: true,
})
.status(200)
.json({...otherDetails});
} catch(err) {
next(err);
}
}
I tried this same thing using promises but still getting the same error I don’t understand why I’m getting this error
But in Postman I’m getting responses like this
Please help me to resolve this error I would be very thankful to you
3
Answers
Did you add the proxy in your package.json?
Can you once try with the following code?
Your front-end and back-end both are on two different ports. If you check your error in your google console it is giving http://localhost:3000 but your backend is on http://localhost:8800.
Now you need to add configuration for axios. Tell him to use http://localhost:8800.
Here we have added http://localhost:8800 as BaseUrl for axios. Now you can use
instance.post("/auth/login", credentials)
in your handleClick methodYou can create a separate file for creating axios instance and use it in where you want to use.
Now you can import instance instead of axios. It will save from configuring axios everytime for every api call.