I am using express-session in my node.js application for authentication. The login route works fine but I am not able to logout. The session remains there in my mongodb database with a new expiration time when the logout link is clicked.
I have tried req.session.destroy() and req.session.cookie.expires = new Date().getTime() for the cookie to get expired when logout button is clicked but nothing worked.
express-session code in index.js
app.use(expressSession({
secret: 'secret',
cookie: { maxAge: 60 * 60 * 24 * 1000 }, //if maxAge is set to anything between 1000 and 9000 the logout button works
resave: false,
saveUninitialized: false,
store: new mongoStore({
mongooseConnection: mongoose.connection
})
}));
loginUser.js
const bcrypt = require('bcrypt')
const User = require('../database/models/User')
module.exports = (req, res) => {
const {
email,
password
} = req.body;
// try to find the user
User.findOne({
email
}, (error, user) => {
if (user) {
// compare passwords.
bcrypt.compare(password, user.password, (error, same) => {
if (same) {
req.session.userId = user._id
res.redirect('/')
} else {
res.redirect('/auth/login')
}
})
} else {
return res.redirect('/auth/login')
}
})
}
storeUser.js
const User = require('../database/models/User')
module.exports = (req, res) => {
User.create(req.body, (error, user) => {
if (error) {
const registrationErrors = Object.keys(error.errors).map(key => error.errors[key].message)
req.flash('registrationErrors', registrationErrors)
return res.redirect('/auth/register')
}
res.redirect('/')
})
}
auth.js
const User = require('../database/models/User')
module.exports = (req, res, next) => {
User.findById(req.session.userId, (error, user) => {
if (error || !user) {
return res.redirect('/')
}
next()
})
}
logout.js
module.exports = (req, res) => {
req.session.destroy(() => {
res.redirect('/auth/login');
});
I expect the session to get destroyed and the page to be redirected to the login page. Can anyone tell me what i am doing wrong?
try this
module.exports = (req, res) => {
if(req.session) {
req.session.cookie.maxAge = 0
delete req.session
}
res.redirect('/auth/login')
}
Related
I am building a project using Firebase, node.js, express.
The issue is that when I deploy the website then the user automatically log out from the website i.e. the user object that I store in session during login initially have some value but after some time (1 minute to 10-15 minutes), the user object is not present in session object and the user is logged out.
Here is the code:
This is index.js
const session = require('express-session');
const functions = require('firebase-functions');
const firebase = require("firebase");
const { firebaseConfig } = require('./config');
const serviceAccount = require("./serviceAccountKey.json");
firebase.initializeApp({ ...firebaseConfig });
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: 'https://<DATABASE-NAME>.firebaseio.com'
});
app.use(session({
name: '__session',
secret: 'somesecret',
resave: true,
saveUninitialized: true,
cookie: {
maxAge: 5 * 24 * 60 * 60 * 1000, // 5 days
secure: false,
httpOnly: true
}
}));
app.use(async(req, res, next) => {
res.locals.success = req.flash('success');
res.locals.error = req.flash('error')
res.locals.currentUser = null;
const currentUser = req.session.currentUser || "";
const uid = currentUser.uid;
if(uid){
if(!res.locals.currentUser)
res.locals.currentUser = await admin.auth().getUser(uid)
}
functions.logger.log(req.originalUrl,"Session: ",req.session)
next();
});
Now the sign up and login routes:
module.exports.basicRegister = async(req, res) => {
const { name, email, password } = req.body;
firebase.auth().createUserWithEmailAndPassword(email, password)
.then(async(userCredential) => {
// Sign-In user and Add details about the user.
var user = userCredential.user;
user.updateProfile({
displayName: name,
}).then(() => {
// Update successful
user.sendEmailVerification()
.then(() => {
// Send verification link and log Out.
firebase.auth().signOut()
.then(() => {
// Sign-out successful.
req.flash('success', "Verification Link has been sent to your email. Please verify email and login on HireUp.")
res.redirect('/');
})
})
})
})
.catch((error) => {
// An error happened.
req.flash('error', error.message);
res.redirect('/basicRegister')
});
}
module.exports.login = (req, res) => {
const { email, password } = req.body;
firebase.auth().setPersistence(firebase.auth.Auth.Persistence.NONE)
.then(() => {
firebase.auth().signInWithEmailAndPassword(email, password)
.then((userCredential) => {
// Sign-in successful.
const user = userCredential.user;
req.session.currentUser = {
uid: user.uid,
email_verified: user.emailVerified,
name: user.displayName,
email: user.email
};
const redirectUrl = req.session.returnTo || `/profile/${user.uid}`
delete req.session.returnTo;
firebase.auth().signOut();
res.redirect(redirectUrl)
})
.catch((error) => {
// An error happened.
req.flash('error', error.message);
res.redirect('/login')
});
})
.catch((error) => {
// Handle Errors here.
var errorCode = error.code;
var errorMessage = error.message;
res.send(error);
});
}
Alright, I've been racking my brain over this for hours now. When I call my 'sign-in' route the passport middleware works fine and returns with a req.user obj, but when I call another route after that, req.user for that other route is undefined. Where exactly have I messed up here? I'm not sure it matters, but I am calling my API routes from a react client.
auth
router.post(
"/sign-in",
passport.authenticate("local"),
async (req, res, next) => {
if (!req.user) console.log("NO USER!*******************");
try {
const user = _.get(req, "user", "");
res.status(200).json(user);
} catch (e) {
console.log({ e });
return res.status(400).json(false);
}
}
);
My Server
app.use(cors());
app.use(cookieparser());
app.use(logger("dev"));
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(
session({
secret: "super",
resave: false,
saveUninitialized: true,
cookie: { secure: false, maxAge: 4 * 60 * 60 * 1000 }
})
);
require("./utils/passport");
app.use(passport.initialize());
app.use(passport.session());
./utils/passport
const _ = require("lodash");
const LocalStrategy = require("passport-local").Strategy;
const { PrismaClient } = require("#prisma/client");
const prisma = new PrismaClient();
const bcrypt = require("bcrypt");
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(async function(id, done) {
console.log("");
console.log("deserializeUser*************************");
console.log("");
try {
const user = await prisma.user.findOne({ where: { id } });
if (!user) {
return done(null, false);
}
return done(null, user);
} catch (e) {
done(e);
}
});
passport.use(
new LocalStrategy(
{
passReqToCallback: true,
usernameField: "email"
},
async (req, email, password, done) => {
try {
const user = await prisma.user.findOne({ where: { email } });
if (!user) {
return done(null, false);
}
await bcrypt.compare(
password,
_.get(user, "password", ""),
(err, result) => {
if (!result) {
done(null, false);
}
done(null, user);
}
);
} catch (e) {
done(e);
}
}
)
);
I suspect something is wrong with the portion where you have your post method with passport authenticate.
This portion may be deleted:
if (!req.user) console.log("NO USER!*******************");
I think the asynchronous may produce here odd results. Then for the sake of troubleshooting, include in your
const user = _.get(req, "user", "");
real data, such as real user data. Thus you will be able to verify that the data is passing through.
I am having an issue with my app with the req.user persisting. After a successful login/serializeUser etc, I can see the req.user in the saved, and the application works as desired for about 1-2 minutes. After that, the req.user clears to undefined. I'm using currently using react and calling a method to the server to confirm there is a req.user on componentDidMount. I have no idea why and I'm pretty new to this.
In my server.js:
app.use(bodyParser.json())
// Sessions
app.use(
express-session({
secret: 'feedmeseymour',
cookie: { maxAge: 60000 },
store: new MongoStore({ mongooseConnection: dbConnection }),
resave: false,
saveUninitialized: false
})
)
// MIDDLEWARE
app.use(morgan('dev'))
app.use(
bodyParser.urlencoded({
extended: false
})
)
app.use(bodyParser.json())
app.use(express.static('public'));
app.use(cors());
app.use(bodyParser.urlencoded({extended: true}));
app.use(bodyParser.json());
// Passport
app.use(passport.initialize())
app.use(passport.session())
My login route:
router.post(
'/',
function (req, res, next) {
console.log('Received login information. Username: ' + req.body.username)
const {errors, isValid } = validateLoginInput(req.body);
if (!isValid) {
return res.status(400).json(errors);
}
next()
},
passport.authenticate('local', {failWithError: true }),
function (req, res, next) {
console.log('req.user in the backend: ' + req.user);
var userInfo = req.user
res.send(userInfo);
},
function (err, req, res, next) {
res.status(401).send({ success: false, message: err })
}
)
passport.serializeUser/deserialize methods:
passport.serializeUser((user, done) => {
console.log('*** serializeUser called, user: ')
console.log(user) // the whole raw user object!
console.log('---------')
done(null, { _id: user._id })
})
// user object attaches to the request as req.user
passport.deserializeUser((id, done) => {
console.log('DeserializeUser called')
User.findOne(
{ _id: id },
'username',
(err, user) => {
console.log('*** Deserialize user, user:')
console.log(user)
console.log('--------------')
done(null, user)
}
)
})
called on componentDidMount:
getUser() {
axios.get('/users').then(response => {
if (response.data.user) {
this.setUser(true, response.data.username, response.data.super);
}
else {
console.log('no user is logged in')
this.setUser(false, null, false);
}
})
}
Which calls this route in the back:
router.get('/', (req, res, next) => {
console.log('req.user:');
console.log(req.user);
console.log('------------');
console.log('req.session:');
console.log(req.session);
console.log('------------');
if (req.user) {
User.findOne({ _id: req.user._id }, (err, user) => {
if (err) {
console.log('logged user retrieval error: ', err)
} else if (user) {
console.log('found user from _id: ' + user);
res.json({ user: req.user, super: user.super })
}
})
} else {
res.json({ user: null })
}
})
req.user exists in the back for about 1-2 minutes and then it goes to undefined. I am storing the user in a store in mongodb, and I can see the session still exists there too.
the req.user is saved with information. In a minute, this will change to undefined:
req.user:
{ _id: 5b7ded93525742053a6dd155, username: 'admin' }
------------
req.session:
Session {
cookie:
{ path: '/',
_expires: 2018-09-09T07:10:22.902Z,
originalMaxAge: 60000,
httpOnly: true },
passport: { user: { _id: '5b7ded93525742053a6dd155' } } }
------------
cookie: { maxAge: 60000 }
That's 60.000 milliseconds, or 60 seconds. Exactly the 1 minute you're describing.
Try storing the user in the session object of the request. This way it works for me.
I'm pretty new to Node.js and Express-session. I have created a login/registration system, whenever the user logs in redirected to a page called scoreboard.
Problem: Session expires very soon, not the value that I have set it. I don't know how to fix it?
server.js
var session = require('express-session');
app.use(session({
secret: "ILoveMostafa",
resave: false,
saveUninitialized: false,
cookie: {
expires: new Date(Date.now() + 43200)
}
}))
user.js
router.post('/login', (req, res) => {
var email = req.body.email;
var password = req.body.password;
userModel.authenticate(email, password, (err, user) => {
if (err) {
console.log(err)
}
else if (!user) {
console.log('Wrong Password')
}
else {
req.session.userId = user._id;
res.redirect('/user/scoreboard')
}
})
});
router.get('/scoreboard',async (req, res) => {
console.log(req.session.userId)
if (req.session.userId) {
const teams = await userModel.find({}).sort('-score')
const faculties = await userModel.aggregate([{
"$group": {
_id: "$faculty",
average: {
$avg: "$score"
}
}
}]).sort("-average")
res.render('main/scoreboard', {
teamInformation: teams,
finalResult: faculties
})
}
else {
res.redirect('/')
}
});
After about 2 minutes when I refresh the page, I redirected to login page!
Date time is measured in milliseconds.
expires: new Date(Date.now() + 43200) is setting the expire time to be 43.2 seconds later than the present time.
I am reading an article about nodejs express module and sessions here
https://www.codementor.io/emjay/how-to-build-a-simple-session-based-authentication-system-with-nodejs-from-scratch-6vn67mcy3
I am confused on this portion of the code
app.use((req, res, next) => {
if (req.cookies.user_sid && !req.session.user) {
res.clearCookie('user_sid');
}
next();
});
from where did the req object get the user property ?
If we look at the article the session object is created like
app.use(session({
key: 'user_sid',
secret: 'somerandonstuffs',
resave: false,
saveUninitialized: false,
cookie: {
expires: 600000
}
So how does this even work
if (req.cookies.user_sid && !req.session.user)
how does the req.cookies.user_id shouldnt it be req.cookies.key ?
How does req.session.user work ?
user is not even a property of the session object no ?
Look further down in the article. There are several instances where req.user is an lvalue. In fact it's entirely up to you to assign to it:
The article posits this code block:
Signup:
// route for user signup
app.route('/signup')
.get(sessionChecker, (req, res) => {
res.sendFile(__dirname + '/public/signup.html');
})
.post((req, res) => {
User.create({
username: req.body.username,
email: req.body.email,
password: req.body.password
})
.then(user => {
/*
* The user just signed up, so let's sign him in
*/
req.session.user = user.dataValues;
res.redirect('/dashboard');
})
.catch(error => {
res.redirect('/signup');
});
});
Logging In:
// route for user Login
app.route('/login')
.get(sessionChecker, (req, res) => {
res.sendFile(__dirname + '/public/login.html');
})
.post((req, res) => {
var username = req.body.username,
password = req.body.password;
User.findOne({ where: { username: username } }).then(function (user) {
if (!user) {
res.redirect('/login');
} else if (!user.validPassword(password)) {
res.redirect('/login');
} else {
/*
* The user just logged in so lets sessionize them
*/
req.session.user = user.dataValues;
res.redirect('/dashboard');
}
});
});