skip to Main Content

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

Error 404 Not Found

But in Postman I’m getting responses like this

Postman respose

Please help me to resolve this error I would be very thankful to you

3

Answers


  1. Did you add the proxy in your package.json?

      "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/"
    
    Login or Signup to reply.
  2. Can you once try with the following code?

    const handleClick = async (e) => {
        const config = {
          url: "http://localhost:8800/api/auth/login",
          data: credentials
        };
    
        e.preventDefault();
        dispatch({ type: "LOGIN_START" });
        try {
          const res = await axios.post(config);
          dispatch({ type: "LOGIN_SUCCESS", payload: res.data });
          navigate("/");
        } catch (err) {
          dispatch({ type: "LOGIN_FAILURE", payload: err.response.data });
        }
    };
    
    Login or Signup to reply.
  3. 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.

    const instance = axios.create({baseURL: 'http://localhost:8800/api'});
    

    Here we have added http://localhost:8800 as BaseUrl for axios. Now you can use
    instance.post("/auth/login", credentials) in your handleClick method

    You can create a separate file for creating axios instance and use it in where you want to use.

    import axios from 'axios';
    const instance = axios.create({baseURL: 'http://localhost:8800/api'});
    export default instance
    

    Now you can import instance instead of axios. It will save from configuring axios everytime for every api call.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search