req.session has no method 'touch'? - node.js

I'm trying to use express-session with connect-redis to store user sessions. Currently, after a user logs in, I return back req.sessionID and then whenever the user wants to make a request to a secure part of the api, he/she has to provide the session ID. The authentication middleware then goes back into redis and checks to see if the session exists and if so, replace the current session with the one stored in Redis.
function isLoggedIn(req, res, next){
var session_id = req.body.session_id;
if (!session_id){
res.send(401, {status: 0, message: "Not authorized"});
return;
}
console.log(req);
sessionStore.get(session_id, function(err, session){
if(err){
res.send(401, {status: 0, message: "Not authorized"});
return;
}
req.session = session;
req.sessionID = req.body.session_id;
return next();
});
}
But for some reason, this error shows up:
/node_modules/express-session/index.js:269
req.session.touch();
^
TypeError: Object #<Object> has no method 'touch'
I can't seem to find anyone else online that has this error because touch() is a built in functionality to express-session. Please help? My express-session version is 1.9.3.

I was having the same error. It seems that if you're coming from express cookie sessions, it was possible to set req.session = {/* some arbitrary session object */}. Obviously, req.session has some methods on the instance that express needs.
So, just make sure you're not explicitly overriding req.session anywhere in your code.

Try this:
req.session.user = { 'id': 123 };
req.session.pageviews = 1; // This too
Font: https://davidburgos.blog/expressjs-session-error-req-session-touch-not-function/

Related

Node w/Express req.session undefined in controller.js

I am new to Node, so this may be obvious. In my app's main.js file, I have a route with a call back function that successfully sets the user's session info ( UserID). Basic example :
App.get("/setID", function(req,res){
req.session.UserID = ‘Fred’;
res.send(“User ID Set”);
})
This works, but I want practice organizing code with routers and controllers. When I move the code to controller.js like this:
Exports.setSessionUserID = function(req,res){
req.session.UserID = ‘Fred’;
res.send(“User ID Set”);
}
I get an error that says that req.session is undefined:
TypeError: Cannot set property 'UserID' of undefined.
If I comment out the req.session line, I do get the res.send successfully, so the router is calling this function correctly.
I belive that controller.js has all of the relevant "requires" (bodyParser, Express-sessions) that are present in main.js.
Why would calling theis function from a controller be any different (regarding sessions) than calling it from main.js?
The only problem here is that you are trying to set a property on req.session which itself is undefined, and you can't do that
// you can do
Exports.setSessionUserID = function(req,res){
req.session = { UserId: `Fred` }
res.send(“User ID Set”);
}
An Example
let req = {};
req.session = { UserId: `Fred` };
console.log(req.session.UserId);

express-session: Why is redirect executed before my session info is set?

Yet another "I've just started learning node.js/express and now I stuck" person here. I've tried looking everywhere for answers but I've reached a dead end. This is my first Stackoverflow question, so please tell me if I have done something wrong or unconventional.
I'm trying to create a POST request that saves a User-object to an express-session (on MongoDB), and redirects you to a URL that handles your session information.
The problem is, that the user is redirected before the header is set, and I am given the following:
Error: Can't set headers after they are sent.
Here is my code. I know it's a lot.. Im sorry.
router.post()
// Handler for POST requests from root page (/)
router.post('/', function(req, res) {
console.log("Router: A POST request for: \"/\" has been called!");
var username = req.body.username;
var password = req.body.password;
// Connect to database
mongoose.connect(dbAddress);
var db = mongoose.connection;
// Report if error in connection
db.on('error', console.error.bind(console, 'Database: Connection error..'));
// Callback function on 'open'
db.once('open', function() {
console.log("Database: Connection successful!");
console.log("Database: User supplied username: " + username);
console.log("Database: User supplied password: " + password);
// Find User object with a userId of req's username
User.findOne({ 'userId' : username.toUpperCase() }, function(err, userObj) {
if (err)
return console.err(err);
// Disconnect when done retrieving user object
mongoose.disconnect();
if ( userObj ) {
console.log("Database: Returned password from MongoDB:");
console.log(userObj.password);
var db_password = userObj.password;
if (password === db_password) {
console.log("Database: User Authenticated");
// Set 'req.session.user' as cookie
req.session.user = userObj;
// Redirect to homepage, with new cookie set
res.redirect('/');
} else { // If passwords don't match
res.render('index', {
showError: true
});
}
} else { // If userObj is null
res.render('index', {
showError: true
});
}
});
});
});
Note the 'req.session.user = userObj' part. Here I am trying to set 'user' in the session to the user object retrieved from MongoDB. In the next line, I am redirecting the user back to the GET request handler for '/' which handles the user based on the session information.
For some reason, these aren't happening in order. The GET request handler doesn't find req.session.user.
I understand that node.js is all about asynchronisation, but from other examples I've found online, this is supposed to work. What am I missing here?
You could put your redirect inside a callback after the session is saved e.g:
...
// Set 'req.session.user' as cookie
req.session.user = userObj;
req.session.save(function(err) {
// session saved
res.redirect('/')
})
...
Hopefully this will make sure that the user is only redirected after the session is saved.
Note: Make sure you hash your password with something like Bcrypt or pbkdf2.

Passport update session isn't persisting

I'm trying to update my user session with a new name, an easy task I thought.
I'm a logged in user and in hitting a 'update' route and I've defined my own middleware to update the session:
module.exports = function(req, res, next) {
console.log(req.user);
req.login(req.body.user, function(err) {
if (err) return next(new Error('Error updating user profile'));
console.log('USER UPDATED *******', req.user);
next();
});
};
It took a bit of time to dig out the above code which should simply update the Passport session object. It correctly logs the previous session, and then the updated session but when I navigate to a new page after the inital response the user object is entirely lost and just returns {}.
Any ideas?
source
To log in a user and persist it into session passport uses a serialize function which typically stores user.id as a cookie and a deserialize function which retrieves that cookie and does a User.findById database call to find the associated user, and if found one, that's the user object that gets stored in req.user.
req.login passes whatever you pass it as the first argument directly to passport.serialize, which otherwise would've typically come from a strategy, which itself would've retrieved the user object from a database call, or created one.
So when you use req.login you need to pass it the user object that passport.serialize actually would've received, so that it could store the id in a cookie.
In your case, you were doing req.login(req.body.user, ... and since req.body.user comes from a POST Form variable it must not have the id that passport.serialize would've stored in the cookie.
You should instead use the new values from req.body.user and update req.user itself, and then do req.login(req.user, ...
var _ = require('lodash');
module.exports = function(req, res, next) {
//using lodash merge the updated user into the cached user
_.merge(req.user, req.body.user);
req.login(req.user, function(err) {
if (err) return next(new Error('Error updating user profile'));
console.log('USER UPDATED *******', req.user);
next();
});
};

How to implement OAuth to my Nodejs/Sails.js app?

I have a sails.js app that generates API to my client. In order to secure my API I need to implement OAuth2.0 to my sails app. I have started to follow this tutorial: https://www.npmjs.com/package/sails-generate-auth#requirements
But I get all kinds of diffrent errors when every time when I try to lift the server. I also dont understand to where i'm suppose to send my credentials to the server and get the access token. I'm fairly new to Sails.js and just got to know OAuth and I can't find a proper guide on how to implement OAuth.
How can I implement OAuth to my app? please have a detailed answer so that I can fully understand.
UPDATE:
ok so instead I started to follow this guide: https://www.bearfruit.org/2014/07/21/tutorial-easy-authentication-for-sails-js-apps/
and I think I got everything to work as it should(?) when I register an account it saves the data in the database as it should. The login also seems to work properly But I didn't understood how I can access the actuall data like the username and email address after the login redirects me to the homepage? I've tested the login on postman and when i log in I get a cookie. What am I suppose to do with it?
The AuthController generated by sails-generate-auth doesn't add the user details to the session by default so you should add it manually by adding the following line to the callback function in AuthController.js
req.session.user = user;
This is how the callback looks like with the line:
callback: function (req, res) {
function tryAgain (err) {
// Only certain error messages are returned via req.flash('error', someError)
// because we shouldn't expose internal authorization errors to the user.
// We do return a generic error and the original request body.
var flashError = req.flash('error')[0];
if (err && !flashError ) {
req.flash('error', 'Error.Passport.Generic');
} else if (flashError) {
req.flash('error', flashError);
}
req.flash('form', req.body);
// If an error was thrown, redirect the user to the
// login, register or disconnect action initiator view.
// These views should take care of rendering the error messages.
var action = req.param('action');
switch (action) {
case 'register':
res.redirect('/register');
break;
case 'disconnect':
res.redirect('back');
break;
default:
res.redirect('/login');
}
}
passport.callback(req, res, function (err, user, challenges, statuses) {
if (err || !user) {
return tryAgain(challenges);
}
req.login(user, function (err) {
if (err) {
return tryAgain(err);
}
// Mark the session as authenticated to work with default Sails sessionAuth.js policy
req.session.authenticated = true;
req.session.user = user;
// Upon successful login, send the user to the homepage were req.user
// will be available.
res.redirect('/');
});
});
}
You can now use the user details in any of your controllers and views by referring to req.session.user for example twitter provides your user name so you can use req.session.user.username.

express.js not saving session data on nodeunit tests

Update at bottom!
My node.js server uses express.js to manage sessions. Upon login, I store some user information in req.session. I have a logout endpoint that simply deletes the user data from req.session before sending its response.
With every request the user makes, I use authentication middleware to make sure there is still user data in the session, so deleting user data in the session object should fail any subsequent authentication.
To test my server, I have a nodeunit test that logs in, calls a few endpoints, logs out, and then attempts to call another endpoint. I would expect the last endpoint to fail in authentication because I previously blew away user data. Instead, when I make the last call, my user data is still there. It's as if the logout call that deleted it was not written back into the session store.
Here's my app.js:
app.use(express.cookieParser('secretPassword'));
app.use(express.cookieSession({key: 'someKey'}));
...
app.get('/logout', accounts.logout);
app.get('/account', auth.authenticateSession, accounts.show);
auth.js:
exports.authenticateSession = function(req, res, next) {
if (!req.session.user) {
return res.json(401, {
error: 'Access denied. You must be logged in to make this request.'
});
}
...
}
accounts.js:logout:
exports.logout = function(req, res) {
req.session.user = null;
res.send('Logged out');
};
Unit tests:
step1_logIn : function(test) {
var postData = qs.stringify({
accountname: 'testAcct',
accountpassword: 'hello'
});
ct.postAndCall('/login', null, postData, function(resData, res) {
myCookie = res.headers['set-cookie'];
test.ok(res.statusCode === 200);
test.done();
});
},
step2_logout : function(test) {
ct.getAndCall('/logout', myCookie, function(data, res) {
test.ok(data === 'Logged out.');
test.ok(res.statusCode === 200);
test.done();
});
},
step3_ensureLoggedOut: function(test) {
ct.getAndCall('/account', myCookie, function(data, res) {
test.ok(res.statusCode === 401);
test.done();
});
}
When the tests run, execution goes through logout successfully, then into authenticateSession on the call to /account and at this point, req.session.user still exists! Why!?
Is my cookie store giving me stale data?
Is there a way to force express to save my session data manually, or do I just modify the req.session object and trust that it's going to save it?
Update:
It looks like this problem is directly related to the app middleware surrounding cookies. When I use app.use(express.session()) instead of app.use(express.cookieSession(...)), the session data is properly blown away and my tests pass.
I figured it out. Apparently express.cookieSession(...) is meant to be a set-once type of storage. Subsequent requests will have access to the session data that was initially set, but changing the req.session object won't save back new session data.
To fix the problem, I switched over to use express.session(...) which uses a server-side store for session vars.

Resources