User sessions data does not persist when calling from a different route - node.js

My user session does not persist within the server. I can see within the log that I saved it in my /login route, but when I try to access it from a different route, its "undefined".
My /login route:
app.route("/login")
.post(async (req, res) => {
var username = req.body.username,
password = req.body.password;
console.log('\t we are here')
try {
var user = await User.findOne({ username: username }).exec();
if(!user) {
res.redirect("/login");
}
user.comparePassword(password, (error, match) => {
if(!match) {
console.log('Password Mismatch');
console.log('Ensure redirect to /login');
res.redirect("/login");
}
});
req.session.user = user;
console.log('\t\treq.session:');
console.log(req.session)
var redir = { redirect: "/dashboard" };
return res.json(redir);
} catch (error) {
console.log(error)
}
});
In the above snippet I try to save the session data by req.session.user = user;. Its log appears as:
But now when I try to call the session I just stored, it shows "undefined". This is my /dashboard route & its corresponding log:
app.get("/dashboard", (req, res) => {
console.log(req.session.user_sid);
// console.log(req.cookies.user_sid);
if (req.session.user && req.cookies.user_sid) {
// res.sendFile(__dirname + "/public/dashboard.html");
console.log(req.session);
res.send("send something")
} else {
res.send("go back to /login");
}
});
To my understanding, user authentication is done my checking sessions and cookies, which is why I'm trying to save the session to request.session. I want to the data to persist so that I can use it in all my other routes such as when calling /dashboard api.
Dashboard api will be call by a protected route like when the user is logged in.

Related

Cannot save User in session data

I am creating a MERN-dashboard, with a login, registration & a dashboard where only logged in Users have access to. Now I've managed to get the user registration and login working, however I seem to be missing something when it comes to saving the User in the express-session.
This is what I use for the login
app.post('/login', async (req, res) => {
const username = req.body.username;
const password = req.body.password;
const newUser = await User.findOne( {
username: username,
})
if (newUser) {
bcrypt.compare(password, newUser.get("passwd"), (error, result) => {
if (result) {
console.log(newUser)
req.session.user = newUser
req.session.loggedIn = true
res.send({newUser, message: 'Successful Login!'})
} else {
res.send({message: 'Wrong password!'})
}
})
} else {
res.send({message: 'User not found.'})
}
})
And this is how my frontend is checking if a User is logged in
app.get('/login', (req, res) => {
if (req.session.user) {
res.send({loggedIn: true, user: req.session.user})
} else {
res.send({loggedIn: false})
}
})
Now, if I log myself in the POST request signals me, that all is fine. However if I reload the page, the GET request tells me I am not logged in.
I have tried reading several articles about express-session but did not manage to find the solution to my problem.
Thank you in advance.

api call getting affected by another api call's validation

not really sure if my title is correct but my problem is that I have this reset password token checker in my api that seems to get affected by another api that finds a specific user, this api has user validation.
Here is what they look like:
//get specific user
router.get('/:id', validateToken, async (req, res) => {
const id = req.params.id
const user = await User.findByPk(id);
res.json(user);
});
//reset-password token check
router.get('/reset-pass', async (req, res) => {
await User.findOne({
where: {
resetPasswordToken: req.body.resetPasswordToken,
resetPasswordExpires: {
[Op.gt]: Date.now()
}
}
}).then(user => {
if(!user) {
res.status(401).json({ error: 'Password reset link is invalid or has expired.'})
} else {
res.status(200).send({
username: user.username,
message: 'Password reset link Ok!'
});
}
});
});
then here is the validateToken
const validateToken = (req, res, next) => {
const accessToken = req.cookies['access-token'];
if (!accessToken)
return res.status(401).json({error: 'User not authenticated!'});
try {
const validToken = verify(accessToken, JWT_SECRET)
req.user = validToken;
if(validToken) {
req.authenticated = true;
return next();
}
} catch(err) {
res.clearCookie('access-token')
return res.status(400).json({error: err}).redirect('/');
}
};
when I comment out the get specific user api the reset password token check works. If I remove validateToken it returns null instead of giving me the username and message.
One of the things I notice is the route param "/:id", that means that literally everything would be processed by get specific user because all routes start with "/", only use params in routes with a prefix like "/user/:id" that way only the routes that starts with "/user" will execute that code.
Change your code to:
//get specific user
router.get('/user/:id', validateToken, async (req, res) => {
const id = req.params.id
const user = await User.findByPk(id);
res.json(user);
});

controller isnt working as it is supposed to

I used MVC to make a NodeJS server and this is one of the controllers:
module.exports.create_user = async function (req, res) {
// console.log(req.body);
// console.log(req.user);
await Company.findOne({ user: req.body.user }, function (err, user) {
if (user) {
return res.redirect('/login');
}
else {
if (req.body.password == req.body.confirm_password) {
Company.create({
"country": req.body.country,
"username": req.body.user,
"password": req.body.password
});
}
else {
console.log('Passwords didnt match');
}
}
});
req.session.save(() => {
return res.redirect('/profile');
})
}
What this code supposed to do?
It searches if a user already exists; if yes, it will redirect to /login.
If no such user exists, it should create a new user and redirect to /profile.
What does this code do?
Regardless of whether the user exists or not, the code always redirects to /login. Also, a user is created in the database, so every time a new user wants to signup, the user needs to signup and then go to sign in to get access to /profile
What is the problem here which doesn't allow redirect to /profile? And how to fix it?
Let me know if you need anything else
Use username instead of user to find a user
Company.findOne({ username: req.body.user });
You are mixing callback style with async/await, await keyword does not affect on your, it will not wait until the query finished. await keyword just working when you wait for a Promise like object (then able object).
I guess you are using mongoose, the current version of mongoose supports Promise return style.
module.exports.create_user = async function (req, res) {
// console.log(req.body);
// console.log(req.user);
try {
// Use `username` instead of `user` to find a user
const user = await Company.findOne({ username: req.body.user }); // callback is not passed, it will return a Promise
if (user) {
return res.redirect('/login');
}
if (req.body.password == req.body.confirm_password) {
await Company.create({ // wait until user is created
"country": req.body.country,
"username": req.body.user,
"password": req.body.password
});
// then redirect page
req.session.save(() => {
return res.redirect('/profile');
});
} else {
console.log('Passwords didnt match');
// what happen when password didn't match
// return res.redirect('/login'); ???
}
} catch (error) {
// something went wrong
// return res.redirect('/login'); ???
}
}
passport.checkAuthentication = async function (req, res, next) {
console.log(req.user);
let auth_status = await req.isAuthenticated() ? "sucess" : "failure";
console.log(`Authentication ${auth_status}`);
// if the user is signed in, then pass on the request to the next function(controller's action)
if (await req.isAuthenticated()) {
return next();
}
// if the user is not signed in
return res.redirect('/login');
}
I did a but more work on this and possibly the controller is working fine and the problem could be in middleware. In the signup case discussed above, the middelware always logs 'Authentication failure' to console.

check if current user is logged In

I have a profile section in my angular app and right now i have 5 users let's say.
I have a route where users have to change the password. I want to verify if users are correctly logged in and has passed authentication and they cannot change password for any other users.
router.get('/change-password/:username', (req, res) => {
User.findOne({
username: req.params.username
}).then(user => {
if (user) {
res.status(200).json(user);
} else if (!user) {
res.status(404).json({
message: 'user not found'
});
}
});
});
what if user A is logged in and he change the parameter to B and then change the password ? is there any way I dont pass parameter and get current user who is logged In
Basically is like this, when you log the user in from back end, you send a response with a token to the front end. You save this token to the local storage to have it in every request to the back end. Them, you use a middleware function to check if the token is provided in the header of the request like a bearer. So the answer is: you don't have to check the auth every request, you just check if the token is provided by middleware and if it is correct.
If you are using express, the most apps use a middleware in the auth service class like this:
module.exports.isAuthorized = function(req, res, next) {
User.findById(req.session.userId).exec(function (error, user) {
if (error) {
return next(error);
} else {
if (user === null) {
var err = new Error('Not authorized! Go back!');
err.status = 400;
return next(err);
} else {
return next();
}
}
});
}
At the node.js routes:
var auth = require('./auth');
// GET route after registering
router.get('/clientPage', auth.isAuthorized, function (req, res, next) {console.log("1114");
res.sendFile(path.join(__dirname + '/../views/clientPage.html'));
});
As you can see, the second param says that before make the request, it will execute the middleware function auth.isAuthorized.

How can i pass the parameter “username” to "/" router with express?

I have a db operation in login post router, when db operation callback success, I got a username value, and how I can pass this username to the "/" router?
router.post('/login', (req, res)=> {
var username = req.body.username;
var password = common.md5(req.body.password + common.MD5_SUFFIX);
db.query(`SELECT * FROM admin_table WHERE username='${username}'`, (err, data)=> {
if (err) {
console.log(err);
res.status(500).send('database error').end();
} else {
if (data.length == 0) {
res.status(404).send('no this admin').end();
} else {
if (data[0].password == password) {
req.session['admin_id']=data[0].ID;
res.redirect('/');
} else {
res.status(404).send('This password is not incorrect!').end();
}
}
}
});
});
router.get('/login',(req,res)=>{
res.render('admin/login.ejs',{layout:'/admin/layout.ejs',title:'Login'});
});
router.get('/',(req,res)=>{
res.render('admin/index.ejs',{layout:'/admin/layout.ejs',title:'Index',username:username});
});
Such as in post login router, I got a username is "ollie", when db operation is ending, the router redirect "/", I can got the username "ollie" in the "/" router .
The simplest way is to use a session. E.g. where you configure the express app, use this:
if (data[0].password == password) {
req.session['admin_id']=data[0].ID;
req.session.username = data.username;
res.redirect('/');
}
Then later you can access that, e.g.
router.get('/route', (req, res) => {
console.log(req.session && req.session.username);
res.end(`Hi ${req.session && req.session.username}`)
});
And please, please, please do not use md5 in any authentication schemes, even example code.

Resources