I am developing a User Login Project where Apis are written in node js and express, UI part is written in HTML and Javascript. These both are two individual projects.
- When User logins, a fetch cal is made in javascript which hits the '/api/login' URL in Node Js.
- If user credentials are valid user object is set in session provided by express-session package. req.session.user = userDetails;
- And in UI on fetch call success, the page redirects to Dashboard.html.
- On rendering Dashboard.html an another api call is made to check the session validity which hits the 'api/dashboard' URL in Node Js.
- Here when I try to get the user object from session, getting undefined.
if (req.session.user) {
res.status(200).json({ message: 'Authenticated', user: req.session.user });
} else {
res.status(401).json({ error: 'Unauthorized' });
}
- Thus getting unauthorized and redirecting back to login page.
Note: I am running the UI project using GoLive extension in Visual Studio Code
API Project files:
server.js
const express = require("express");
const mongoose = require("mongoose");
const cors = require("cors");
const cookieParser = require("cookie-parser");
const session = require("express-session");
const { config } = require("dotenv");
config();
const registerRouter = require("./routes/register");
const loginRouter = require("./routes/login");
const app = express();
app.use(cors({ origin: "http://XXX.X.X.X:5500", credentials: true }));
app.use(express.json());
app.use(cookieParser());
app.use(
session({
secret: "This is a secret",
resave: false,
saveUninitialized: true,
cookie: { maxAge: 1 * 60 * 1000, httpOnly: true },
})
);
mongoose.connect(process.env.ATLAS_URL, {
useNewUrlParser: true,
});
const db = mongoose.connection;
db.on("error", (error) => console.log(error));
db.once("open", () => console.log("Connected"));
app.use("/api", registerRouter);
app.use("/api", loginRouter);
app.listen(process.env.PORT, () => {
console.log("app is listening on Port " + process.env.PORT);
});
login.js
const express = require("express");
const User = require("../models/User");
const router = express.Router();
router.post("/login", async (req, res) => {
try {
const user = await User.findOne({
email: req.body.email,
password: req.body.password,
});
if (user == null)
res.status(401).json({ error: "Invalid email or password" });
else {
let userSession = {
firstName: user.firstName,
lastName: user.lastName,
email: user.email,
};
if (req.session.user) {
res.status(200).json({ message: "User login Successful" });
} else {
req.session.user = userSession;
// console.log(req.session);
// res.cookie('user',userSession);
res
.status(200)
.json({ message: "User login Successful for first time" });
}
}
} catch (error) {
console.log(error);
res.status(500).send(error);
}
});
router.get("/logout", (req, res) => {
req.session.destroy();
res.status(200).json({ message: "Logout successfull" });
});
router.get("/dashboard", (req, res) => {
console.log("hit");
console.log(req.session);
console.log(req.session.user);
if (req.session.user) {
res.status(200).json({ message: "Authenticated", user: req.session.user });
} else {
res.status(401).json({ error: "Unauthorized" });
}
});
module.exports = router;
UI Project Files:
ui-login.js
var loginUrl = "http://localhost:3000/api/login";
$(document).ready(function () {
$('#loginForm').submit(()=>{
var email = $('#email').val();
var password = $('#password').val();
if(email.trim() == "") {$('#emailError').show(); return false;} else $('#emailError').hide();
if(password.trim() == "") {$('#passwordError').show(); return false;} else $('#passwordError').hide();
const data = {
email: email,
password: password
};
const requestOptions = {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data),
credentials: 'include'
};
fetch(loginUrl, requestOptions)
.then(response => {
if(!response.ok){
if(response.status == 400){
$('#loginError').text(response);
$('#loginError').show();
}else{
throw new Error("User Login failed!");
}
}
return response.json();
})
.then((data)=>{
$('#loginError').hide();
alert(data.message);
window.location.href = '/pages/dashboard.html';
return false;
})
.catch(error =>{
console.log(error);
});
return false;
});
});
ui-dashboard.js
var dashboardUrl = "http://localhost:3000/api/dashboard";
const checkSession = () => {
fetch(dashboardUrl, {
method: "GET",
credentials: "include"
})
.then((response) => {
if (response.status != 200) {
alert("Unauthorized. Redirecting to login page.");
window.location.href = "/pages/login.html";
}
})
.catch((error) => {
console.error("Error:", error);
alert("Error checking session");
window.location.href = "/pages/login.html";
});
};
checkSession();
In Network call, getting session id in response header but not getting user object I had set in session.

In Dashboard network call, no session is sent in request header.

Exhausted figuring out the issue. Thanks in Advance!
I tried many things like setting credentials to true in api calls. Setting cors in Nodejs. Retrieving set-cookie from response header in JavaScript. Tried many online references. At last also tried ChatGPT.
But could not sort out the issue.
Am I in right direction?
Finally fixed it. JavaScript and browser needs to be blamed. After some research got to know that browser won't send cookies to different domains even after setting 'credentials' : 'include' in fetch headers. Thus only way to fix it is to run both UI and API in same domain. I tried running both UI and API in same domain i.e. localhost but different port numbers. That's it issue got fixed.
Reference helped to find out the solution. Credentials: 'include' not including Cookie header