Client is a React app. Server uses express, express-session passport, cors, and body-parser.
Passport JS deserializeUser not being called at when I check if user is logged in from my client webpage, or when user logs out from client webpage. BUT IT IS being called when I test with Postman when checking if user is logged in (GET localhost:5000/api/auth/is_logged_in) or when logging out (GET localhost:5000/api/auth/logout)
I can confirm deserializeUser is being called by using console.log() and by placing breakpoints in my code. All works well with Postman.
I have created a middleware function isLoggedIn
Why is my isLoggedIn middleware working in Postman, but not in my React app client?
server - index.js
const express = require('express');
const bodyParser = require('body-parser');
const cors = require('cors');
const session = require('express-session');
const passport = require('passport');
const LocalStrategy = require('passport-local').Strategy;
const bcrypt = require('bcrypt');
require("dotenv").config();
const port = process.env.PORT;
const baseUrl = process.env.BASEURL;
const app = express()
app.use(cors());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.set('trust proxy', 1);
// passport and session startup - start vvvv
const userQuery = require('./db/userQueries');
// configure passport LocalStrategy
passport.use(
new LocalStrategy(
{
usernameField: 'email',
passwordField: 'password'
},
async (username, password, done) => {
const errMsg = 'Incorrect username or password';
try {
const user = await userQuery.findUserByEmail(username);
// if did not find user
if (!user) return done(null, false, { message: errMsg });
// found user, try to match hashed password
const matchedPassword = await bcrypt.compare(password, user.password_hash);
// if password hashes do not match
if (!matchedPassword) return done(null, false, { message: errMsg });
// password hashes match
return done(null, user);
} catch (err) {
return done(err);
}
}
)
);
// passport serializeUser/deserializeUser
passport.serializeUser((user, done) => {
done(null, user.guid);
});
passport.deserializeUser( async (guid, done) => {
const user = await userQuery.findUserByGuid(guid);
return done(null, user);
});
// session configuration
// app.use(session) BEFORE app.use(passport....)
// NOTE: for local testing, set cookie: secure to false.
// setting cookie: {secure: true} , the cookie will only be set over an
// https connection, and not over an http connection
// https://stackoverflow.com/questions/71184167/why-setting-the-cookie-secure-to-true-in-express-session-allows-session-id-and-d
app.use(session({
secret: process.env.SESSION_SECRET || 'not_so_secret',
resave: true,
cookie: {
maxAge: 1000 * 60 * 60 * 24,
secure: false,
httpOnly: true,
path: '/'
},
saveUninitialized: true
}));
// passport configuration
app.use(passport.initialize());
app.use(passport.session());
// passport and session startup - end ^^^^
// routes
const authRouter = require('./routes/auth');
app.use('/api/auth', authRouter);
app.listen(port, () => {
console.log(`Server started on port ${port}.`)
});
module.exports = app;
server - auth.js
const express = require('express');
const authRouter = express.Router();
const passport = require("passport");
authRouter.post('/register', async (req, res) => {
});
authRouter.post('/login', (req, res, next) => {
passport.authenticate('local', (err, theUser, failureDetails) => {
if (err) {
res.status(500).json({ message: "Something went wrong authenticating user" });
return;
}
if (!theUser) {
res.status(401).json(failureDetails);
return;
}
// save user in session
req.login(theUser, (err) => {
if (err) {
res.status(500).json({ message: "Session save went bad." });
return;
}
res.status(200).json({ errors: false, user: theUser });
});
})(req, res, next);
});
authRouter.get('/logout', (req, res, next) => {
req.logout(err => {
if (err) {
return next(err);
}
res.redirect(`/login`);
})
})
function loggedIn(req, res, next) {
if (req.isAuthenticated()) {
next();
} else {
res.status(401).send('not logged in');
}
};
authRouter.get('/is_logged_in', loggedIn, (req, res) => {
res.status(200).send("User logged in")
});
authRouter.get('/login', (req, res) => {
res.send('Login Page');
});
module.exports = authRouter;
server - app.js
import React, { Fragment } from 'react';
import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';
import Header from './components/Header';
import LogIn from './components/LogIn';
import Register from './components/Register';
import LogOut from './components/LogOut';
import Home from './components/Home';
import './App.css';
function App() {
const isLoggedIn = async () => {
const response = await fetch(`${baseApi}/auth//is_logged_in`);
if (response.status === 200) {
return true
} else {
return false
}
}
const checkedLoggedIn = async () => {
let loggedInStatus = ""
if (await isLoggedIn()) {
loggedInStatus = "Yes, Logged in"
} else {
loggedInStatus = "NOT Logged in"
}
document.getElementById("testData").value = loggedInStatus
}
return (
<Router>
<Fragment>
<Header ref={headerRef} />
<button onClick={checkedLoggedIn}>Test</button>
<input type="text" id="testData" name="testData" ></input>
</Fragment>
<Routes>
<Route
path="/login"
element={<LogIn />}
/>
<Route
path="/register"
element={<Register />}
/>
<Route
path="/logout"
element={<LogOut />}
/>
<Route exact path="/" element={<Home />} />
</Routes>
</Router>
);
}
export default App;
server - logon.js
try {
const loginBody = {
email: sanitized.email,
password: formData.password
}
const response = await fetch(`${baseApi}/auth/login`, {
method: "POST",
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify(loginBody)
});
// successfull login
if (response.status === 200) {
} else if (response.status === 401) {
} else if (response.status === 500) {
} else {
console.error('Login request failed with status:', response.status);
}
} catch (err) {
console.error(err.message);
}
When I test via Postman, in isLoggedIn, req.session.passport has an object with user id. req.session.user has a user object, and req.IsAuthenticated() returns true.
When I test via my React app, in isLoggedIn, req.session.passport and req.session.user properties are not available. Also, req.IsAuthenticated() returns false.