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.
*in cors to the url of your react frontend.fetch("http://localhost:3000/user")tofetch("http://192.168.1.20:3000/user")something in your react code, depending upon your local-ip.