Req.id becomes unavailable after making code updates - node.js

I'm not sure if this is a cookie issue or something else.
When logging in i can make a post, and do other things a user can do. However when i make an update on my code this error shows
TypeError: Cannot read property 'id' of undefined
it doesn't matter if im deleting a post, making a new post, or liking a post.
I would have to logout, and log back in to make things work again.
TLDR: Have to logout, for every code update
this is the session along with other useful info
App.js
app.use(logger('dev'));
app.use(express.static(path.join(__dirname, 'public')));
app.use(express.static(path.join(__dirname, 'build')));
app.use(cookieParser());
app.use(session({
secret : process.env.JWT_SECRET,
saveUninitialized: true,
cookie:{
maxAge: 24 * 60 * 60 * 1000
},
resave: true
}));
app.use(passport.initialize());
app.use(passport.session());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended:false}));
app.use(cors({
origin: process.env.ALLOW_ORIGIN,
credentials: false,
allowedHeaders: 'X-Requested-With, Content-Type, Authorization',
methods: 'GET, POST, PATCH, PUT, POST, DELETE, OPTIONS'
}))
app.use('/api/users', userRoute );
app.use('/api/posts', postRoute );
logIn backend
router.post('/loginUser', passport.authenticate('login', {session: true}), (req, res, next) => {
passport.authenticate('login', (err, user, info) => {
if (err) {
console.log(err);
}
if (info != undefined) {
console.log(info.message);
res.status(401).send(info.message);
} else {
req.logIn(user, err => {
models.User.findOne({
where: {
username: req.body.username,
},
})
.then(user => {
const token = jwt.sign({ id: user.id }, process.env.JWT_SECRET);
res.cookie("jwt", token, { expires: new Date(Date.now() + 10*1000*60*60*24)});
req.session.save( () => {
res.status(200).send({
auth: true,
token: token,
message: 'user found & logged in',
});
})
// console.log(req.user)
});
});
}
})(req, res, next);
});
Passport strategy
passport.use(
'login',
new localStrategy(
{
usernameField: 'username',
passwordField: 'password',
session: false
},
(username, password, done, req) => {
try {
models.User.findOne({
where: {
[Op.or]: [
{
username: username,
}
],
},
}).then(user => {
if (user === null) {
return done(null, false, { message: 'Username doesn\'t exist' });
} else {
bcrypt.compare(password, user.password).then(response => {
if (response !== true) {
console.log('passwords do not match');
return done(null, false, { message: 'passwords do not match' });
}
console.log('user found & authenticated');
// note the return needed with passport local - remove this return for passport JWT
return done(null, user);
});
}
});
} catch (err) {
done(err);
}
},
),
);

Related

ExpressJS Session Authentication with Passport and Mongoose Throwing EPERM renaming error

I'm just getting into MEAN-stack/general Nodejs stuff recently after years of PHP/MySQL web development and I'm looking at authentication. I used this guide to create a simple authentication server with Passport and json-server. It works exactly as described in that guide.
However, I want to be using mongoose/MongoDB for the project I'm learning with so I decided to try and alter the code in that guide to work for mongoose.
All seemed to be going fine (the '/authrequired' endpoint can't be hit without having a cookie that matches a session on the ExpressJS server and login functionality works) but I tried adding registering functionality and I'm getting a renaming error I've never seen before and can't find much information on in this context.
The registering code works fine from mongoose's point-of-view but when I try and call req.login() which should set the session using passport and redirect to '/authrequired' (which is a guarded area requiring a session), I get kicked back to '/' (which is what happens when '/authrequired' can't authenticate the user).
The error I get is:
Error: EPERM: operation not permitted, rename 'C:\Users\admin\express-auth\server\sessions\39cad5de-5e1b-4319-b967-c77dd3ef729d.json.4139658133' -> 'C:\Users\admin\express-auth\server\sessions\39cad5de-5e1b-4319-b967-c77dd3ef729d.json'
I don't understand why express is trying to rename the session file in the first place. If I look in the sessions folder there are 2 files:
39cad5de-5e1b-4319-b967-c77dd3ef729d.json
39cad5de-5e1b-4319-b967-c77dd3ef729d.json.4139658133
The first has the json session data, the second one is blank.
Does anyone know what is going on? What have I done wrong and what can I do to resolve this?
I was not getting this renaming error using the json-server/axios version described in the linked guide.
Thanks
Passport Configuration
passport.use(new LocalStrategy(
{ usernameField: 'email' },
(email, password, done) => {
User.findOne({email: email}, (err, user) => {
if(!user) {
return done(null, false, { message: 'Invalid credentials.\n' });
}
if(!bcrypt.compareSync(password, user.password)) {
return done(null, false, { message: 'Invalid credentials.\n' });
}
return done(null, user);
});
}
});
passport.serializeUser((user, done) => {
done(null, user.id);
});
passport.deserializeUser((id, done) => {
User.findById(id, (err, user) => {
if(user) {
done(null, user);
}
else if(err) {
done(error, false);
}
});
});
app setup
// create the server
const app = express();
// add & configure middleware
app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json())
app.use(session({
genid: (req) => {
return uuid() // use UUIDs for session IDs
},
store: new FileStore(),
secret: 'keyboard cat',
resave: false,
saveUninitialized: true
}))
app.use(passport.initialize());
app.use(passport.session());
Register endpoint
app.post('/register', (req, res, next) => {
User.findOne({email: req.body.email}, (err, user) => {
if(user) {
res.send('Account with email already exists.');
} else {
console.log(req.body.password);
bcrypt.hash(req.body.password, null, null, (err, hash) => {
if(err) { return next(err); }
var newUser = new User({
username: req.body.username,
email: req.body.email,
password: hash,
passwordConf: hash
});
newUser.save((err, savedUser) => {
console.log(savedUser);
if(err) {
return res.send('error saving user.');
}
else {
req.login(savedUser, (err) => {
if(err) { return next(err); }
return res.redirect('/authrequired');
});
}
});
});
}
});
});
Login endpoint
app.post('/login', (req, res, next) => {
passport.authenticate('local', (err, user, info) => {
if(info) {return res.send(info.message)}
if (err) { return next(err); }
if (!user) { return res.redirect('/login'); }
req.login(user, (err) => {
if (err) { return next(err); }
return res.redirect('/authrequired');
});
})(req, res, next);
});
Authrequired endpoint
app.get('/authrequired', (req, res) => {
if(req.isAuthenticated()) {
res.send('you hit the authentication endpoint\n')
} else {
res.redirect('/')
}
});
I was facing a similar issue. I realized that both of us had session declared twice.
app.use(session({
genid: (req) => {
return uuid() // use UUIDs for session IDs
},
store: new FileStore(),
secret: 'keyboard cat',
resave: false,
saveUninitialized: true
}))
app.use(passport.initialize());
app.use(passport.session());
The error disappeared when I removed the first session declaration.
app.use(session({
genid: (req) => {
return uuid() // use UUIDs for session IDs
},
store: new FileStore(),
secret: 'keyboard cat',
resave: false,
saveUninitialized: true
}))

req.user clears after 1-2 minutes using passport.js

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.

expression session how does it work

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');
}
});
});

Passport session is not presisting

Hi I am trying to implement login with passport-local strategy. For some odd reason my code works when I send request from postman, but when I call the same action from my angular project it dose not work. Tracing down the problem I figured out:
When I send request from postman the session looks like this:
Session {
cookie: {
path: '/',
_expires: null,
originalMaxAge: null,
httpOnly: true
},
passport: {
user: 58f0865eb9b69e1d38fa135b
}
}
When I send request from angular the session looks like this:
Session {
cookie: {
path: '/',
_expires: null,
originalMaxAge: null,
httpOnly: true
}
}
because of with passport strategy fails to deserialize user. I have no clue why this is happening, any help will be highly appreciated.
Server code :
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(expressValidator({
customValidators: {
isArray: function (value) {
return Array.isArray(value);
}
},
errorFormatter: function (param, msg, value) {
var namespace = param.split('.')
, root = namespace.shift()
, formParam = root;
while (namespace.length) {
formParam += '[' + namespace.shift() + ']';
}
return {
param: formParam,
msg: msg,
value: value
};
}
}));
app.use(cookieParser());
app.use(expressSession({ secret: 'untoldstoryofninja', resave: false, saveUninitialized: true }));
app.use(cors());
app.use(passport.initialize());
app.use(passport.session());
// routes ========================================================================================
app.use(require('./config/routes/routes.js')(passport));
app.all('*', (req, res) => res.status(404).send({ msg: 'No API Route.' }));
passport strategy:
module.exports = function (passport) {
passport.use(new LocalStrategy({ usernameField: "username", passwordField: "password" },
function (username, password, done) {
User.findOne({ username: username }, function (err, user) {
if (err) { return done(err); }
if (!user) { return done(null, false); }
if (user.comparePassword(password, function (err, isMatch) {
if (isMatch && !err) {
done(null, user)
} else {
done(null, false);
}
}));
});
}
));
passport.serializeUser(function (user, done) {
done(null, user._id);
});
passport.deserializeUser(function (id, done) {
User.findById({ _id: id }, function (err, user) {
done(err, user);
});
});
};
You need to do
passReqToCallback: true
passport.use(new LocalStrategy({
usernameField: 'email',
passwordField: 'passwd',
passReqToCallback: true,
session: false
},
function(req, username, password, done) {
// request object is now first argument
// ...
}
));
also make sure your field names matches with
sernameField: 'email',
passwordField: 'passwd',

MongoStore, Passport-local - Sessions are not being stored in db

I have a Node.js Express App and I am trying to use MongoStore to save the sessions and Passport-local for authentication. The app is not storing sessions in db.sessions
app.js
var session = require("express-session");
var MongoStore = require("connect-mongo/es5")(session);
var passport = require('passport');
app.use(session({
secret: 'secret',
resave: false,
saveUninitialized: false,
duration: 30 * 60 * 1000,
activeDuration: 5 * 60 * 1000,
store: new MongoStore({
url: MongoDB.MONGODB_URL
})
}));
app.use(passport.initialize());
passport.serializeUser(function(user, done) {
done(null, user._id);
});
passport.deserializeUser(function(id, done) {
db.users.findById(id, function(err, user){
if(!err) done(null, user);
else done(err, null);
});
});
localstrategy is implemented as follows. MongoDB is my own module which interacts with MongoDB.
passport.use('local', new LocalStrategy({
usernameField: 'email',
passwordField: 'password'
},
function (email, password, done) {
process.nextTick(function () {
MongoDB.collection("users").findOne({
email: email
}, function (error, doc) {
if (error) {
return done(error);
}
if (doc) {
if (doc.password === PasswordManager.encryptPassword(password)) {
return done(null, doc);
} else {
return done("Invalid Password", false);
}
}
});
});
}
));
Authentication Request.
As I am trying to use MongoStore sessions, I have passed the option - {session: false} to the req.LogIn function.
router.post('/login', function (req, res, next) {
passport.authenticate('local', function (err, user) {
if (err) {
return next(err);
}
if (!user) {
return res.status(401).send({
success: false,
error: "User not found!",
data: null
});
}
req.logIn(user, {session: false}, function (err) {
if (err) {
return next(err);
}
req.session.user = user;
return res.send({
success: true,
error: null,
data: user
});
})
})(req, res, next);
});

Resources