0

I am utilizing a Node.js and express backend with a React frontend. Currently, I am using Passport.js with their Local Authentication Strategy. Whenever I log in on my React login component, it works fine in the Node.js app.post("/login") callback. However, whenever I go to a different page using react router, or I simply refresh, I print out req.user in my react frontend which returns undefined.

Backend

Below, if you go to app.post("/login"), you'll see I print out req.user and req.isAuthenticated(). Req.user returns the user object, and req.isAuthenticated() returns true. However, whenever I refresh or go to another link using react-router, my frontend returns that req.user is undefined when it gets the information from the backend from the app.get("/get-user") route.

require("dotenv").config();
const express = require("express");
const mongoose = require("mongoose");
const cors = require("cors");
const passport = require("passport");
const LocalStrategy = require("passport-local");
const cookieParser = require("cookie-parser");
const bcrypt = require("bcrypt");
const session = require("express-session");

const app = express();

mongoose.connect("mongodb+srv://tacobellcommercial:"+process.env.PASSWORD+"@cluster0.gh4uyob.mongodb.net/")

app.use(express.json());

app.use(cors({
    origin: "*"
}))

app.use(session({
    secret: process.env.SECRET,
    resave: false,
    saveUninitialized: false
}))


app.use(passport.initialize());
app.use(passport.session());
app.use(passport.authenticate("session"));

/* PASSPORT LOCAL STRATEGY */
passport.use(new LocalStrategy(function verify(username, password, callback){
    User.find({username: username}).then(array=>{
        if (array.length === 0){
            console.log("IN HERE")
            return callback(null, false, {message: "Incorrect username or password..."})
        }else{
            bcrypt.compare(password, array[0].password).then((result)=>{
                if (result){
                    console.log("YES")
                    return callback(null, array[0], {message: "Successfully logged in..."})
                }else{
                    console.log("NOPE");
                    return callback(null, false, {message: "Incorrect username or password"})
                }
            })
        }

    })
}))

passport.serializeUser((user, callback)=>{
    callback(null, user.username);
})

passport.deserializeUser((username, callback)=>{
    User.find({username: username}).then(user=>{
        console.log(user[0]);
        callback(err, user[0]);
    })
})


/* MONGOOSE */

const userSchema = new mongoose.Schema({
    username: String,
    password: String
})

const User = mongoose.model("User", userSchema);

/*ROUTES*/

app.post("/login", (req, res, next)=>{
    passport.authenticate("local", (error, user, message)=>{
        console.log("called");
        if (error){
            console.log(error);
            console.log("in error");
            res.json({message: error});
        }else if (!user){
            console.log("in no user");
            res.json({message: "No user exists..."});
        }else{
            console.log("User found and password matches...")
            req.login(user, (err)=>{
                if (err){
                    res.json({message: "Failed to login"})
                }else{
                    console.log("Logged in successfully...")
                    res.json({message: "Success"})
                    console.log("Logged in " + req.isAuthenticated());
                    console.log(req.user);
                }
            })
        }
    })(req, res, next);
})

app.post("/register", (req, res)=>{
    User.findOne({username: req.body.username}).then((object)=>{
        if (object){
            console.log(object)
            console.log(req.body);
            res.json({message:"User exists"});
        }else{
            console.log("hi");
            const newUser = new User({
                username: req.body.username,
                password: req.body.password
            })
            newUser.save().then(userObject=>{
                console.log("Saved user object");
                res.json({message: "Success"})
            })
        }
    })
})

app.get("/user", (req, res)=>{
    console.log(req.user);
    res.send({message: req.user});
})


/**/


app.listen(3000, ()=>{
    console.log("Server started");
})

Frontend

Login Component

import React from "react";
import UserContext from "../Context";
import { Navigate } from "react-router-dom";
 
function Login(){

    const [username, setUsername] = React.useState("")
    const [password, setPassword ] = React.useState("")
    const [redirect, setRedirect] = React.useState(false);

    const {login} = React.useContext(UserContext)
    
    React.useEffect(()=>{
        fetch("http://localhost:3000/user", {
            method: "GET",
            headers: {
                "Content-Type": "application/json"
            }
        }).then(res=>{
            return res.json();
        }).then(data=>{
            console.log(data);
        })
    }, [])

    return(
        <form className="login" onSubmit={(event)=>{
            event.preventDefault();
            
            const result = login(username, password);
            result.then(data=>{
                if (data.message === "Success"){
                    setRedirect(true);
                }
            })
        }}>
            {redirect ? <Navigate to="/"/> : null}
            <h1>Username</h1>
            <input placeholder="Username" onChange={(event)=>{
                setUsername(event.target.value);
            }}/>
            <h1>Password</h1>
            <input placeholder="Password" onChange={(event)=>{
                setPassword(event.target.value);
            }}/>

            <button type="submit">Make account</button>
        </form>  
    )
}

export default Login;

Context

import React from "react";

const UserContext = React.createContext();

export function UserContextProvider({children}){

    function register(username, password){
        fetch("http://localhost:3000/register", {
            method: "POST",
            data: {
                username: username,
                password: password
            }
        }).then(res=>{
            return res.json();
        }).then(data=>{
            console.log(data)
        })
    }

    function login(username, password){
        const data = fetch("http://localhost:3000/login", {
            method: "POST",
            headers: {
                "Content-Type": "application/json"
            },
            body: JSON.stringify({username: username, password: password})
        }).then(res=>{
            return res.json();
        }).then(data=>{
            console.log(data);
            return data;
        })

        return data;
    }

    return(
        <UserContext.Provider value={{register, login}}>{children}</UserContext.Provider>
    )
}


export default UserContext;

App.jsx (this is where I console.log(data) where it's supposed to be req.user and it returns undefined in React.useEffect!)

import React from "react";
import {Route, Routes, Link} from "react-router-dom";
import Login from "./components/Login";
import Register from "./components/Register";
import {UserContextProvider} from "./Context";

function App(){
    
    React.useEffect(()=>{
        fetch("http://localhost:3000/user", {
            method: "GET",
            headers: {
                "Content-Type": "application/json"
            }
        }).then(res=>{
            return res.json();
        }).then(data=>{
            console.log(data);
        })
    }, [])

    return(
        <UserContextProvider>
            <div className="header">
                <div className="navbar">
                    <Link to="/login">Login</Link>
                    <Link to="/register">Register</Link>
                </div>
                <Routes>
                    <Route path="/login" element={<Login/>}/>
                    <Route path="/register" element={<Register/>}/>
                </Routes>
            </div>
            
        </UserContextProvider>
    )
}

export default App;

I've researched this for around 7 hours straight and I can't find out what I did wrong.

6
  • Can you try replacing * in cors to the url of your react frontend. Commented Jun 22, 2023 at 13:03
  • Put it to origin: "localhost:3001" but does not work regardless, it fails to fetch with an error saying it was blocked by the cors policy. Commented Jun 24, 2023 at 7:01
  • 1
    can you instead try to serve your react frontent on local ip, eg."192.168.1.20:3000" something. What you are using to bundle react Commented Jun 24, 2023 at 7:22
  • I tried what you said, I bundled react using my local IP on my network and set the same IP to the list of allowed origins in the cors modification. It still does not work and returns undefined when trying to print req.user Commented Jun 25, 2023 at 8:21
  • 1
    Try to do the same for the server, change fetch("http://localhost:3000/user") to fetch("http://192.168.1.20:3000/user") something in your react code, depending upon your local-ip. Commented Jun 26, 2023 at 6:49

1 Answer 1

0

The problem seems to be in fetch request that your are making. You just need to add credentials:"include" option in fetch , in order for the browser to send credentials (cookies,auth etc.) with the request.

Do this for all the requests,

fetch("http://localhost:3000/user", {
        method: "GET",
        headers: {
            "Content-Type": "application/json"
        },
        credentials:"include"
    })

I think you also need to set the credentials:true in cors in your backend.

Sign up to request clarification or add additional context in comments.

3 Comments

Does not work, tested with both local ip and localhost in the address; still returns undefined. Added credentials in all post and get requests, added credentials: true in the cors configuration, and set the origin "localhost:3001" to be allowed in the cors origin configuration as react was running on port 3000.
@Chris Why are you using localhost(remove completely), please only use local ip address ("192.168.1.20" something) for now. Also in desrializeUser function, is it logging the correct user information?
Yes, it is logging the correct user information

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.