client-sessions nodejs / Express - error: Cannot set property 'mydata' of undefined - node.js

I'm trying to use the client-sessions middleware in nodejs / Express and I get the following error: Cannot set property 'mydata' of undefined.
I've also looked at this post, but could not find additional clues as to why I may be getting the error. node-js-client-sessions-not-creating-req-session
var bodyParser = require('body-parser');
const express = require('express');
const app = express();
const clientSessions = require("client-sessions");
var urlencodedParser = bodyParser.urlencoded({ extended: false });
var router = express.Router();
app.use(clientSessions({
cookieName: 'mydata', // cookie name dictates the key name added to the request object
secret: 'longsecretkeyorwhatever', // should be a large unguessable string
duration: 24 * 60 * 60 * 1000, // how long the session will stay valid in ms
activeDuration: 1000 * 60 * 5 // if expiresIn < activeDuration, the session will be extended by activeDuration milliseconds
}));
/* Form POST handler */
router.post('/', urlencodedParser, function(req, res) {
if (!req.body) return res.sendStatus(400);
if(req.body.firstName){
req.session_state.mydata = req.body.mydata;
}
})

The documentation of client-sessions explains:
cookie name dictates the key name added to the request object
Since you're setting firstName as cookie name, the session object is available as req.firstName:
req.firstName.mydata = req.body.mydata

Related

I can't create a cookie using node-client-sessions

I am building a NodeJS web server, mostly static files (jade to come) but I am at the point where I want to be able authenticate the user and all was going fine until I hit a speed bump with setting cookies.
I am using express & client-sessions and I am almost verbatim example code.
No matter what I am doing I don't seem to be able set a cookie.
Code below I am hoping there's a simple gotcha I have missed!
** Versions **
NodeJS: v 6.2
client-sessions: 0.7.0
//** Required files
var express = require("express");
var bodyParser = require("body-parser");
var sessions = require("client-sessions");
var app = express();
var port = 8080;
var svr = app;
//** Middleware
app.use(express.static(__dirname + '/Public')); //** Use express globally to catch all requests and direct to Public folder
app.use(bodyParser.urlencoded({extended: false})); // create application/x-www-form-urlencoded parser
app.use(bodyParser.json()); // create application/json parser
app.use(sessions({
cookieName: 'mySession', // cookie name dictates the key name added to the request object
secret: 'kdheiuehiygft', // should be a large unguessable string
duration: 24 * 60 * 60 * 1000, // how long the session will stay valid in ms
activeDuration: 1000 * 60 * 5 // if expiresIn < activeDuration, the session will be extended by activeDuration milliseconds
}));
app.get("/", function(req, res){
req.mySession.seenyou = true;
res.setHeader('X-Seen-You', 'false');
res.sendFile(__dirname + "/index.htm");
});
The reasons appears to be that Express was "capturing" the input prior to me setting anything and redirecting to the index.html file in Public.
Having now created a separate login page which POST's the data to a new route, all works fine!

node.js session values aren't accessible in second api call

i am facing the following issue:
(I am using node-client-sessions module)
I send an ajax request, through the browser, to my API : /api/request1
In my api.js I handle that request, calculate some stuff and write some results into the session like this.
router.post('/request1', function(req, response, next) {
// some wield calculations
req.session.calcData = { // some content }; 
// some other calculations
console.log(req.session.calcData); // logs the correct object
response.send('success');
}
After receiving the success on client side I send another api call like this for example: /api/request2
router.post('/request2', function(req, response, next) {
// here i want to use some of the results from the previous calculations which i stored in the calcData session.
console.log(req.session.calcData); // this logs undefined
}
Shouldn't req.session.calcData be available in both functions?
Enviroment Info
Express Framework 4.x
app.js :
...
var app = express();
...
var session = require('client-sessions');
...
app.use(session({
cookieName: 'session',
secret: 'random_string_goes_here',
duration: 30 * 60 * 9999999,
activeDuration: 5 * 60 * 1000,
}));
...
app.use('/api', api);
According to example at client-session, you must use req.csession and req.csflush();
var express = require('express');
var path = require('path')
var cs = require('client-session');
var clientSession = cs('mysecretkey');
var app = express();
app.use(clientSession.connect());
app.get('/', function(req, res){
var count = req.csession['count'];
if(!count) count = 1;
else count++;
req.csession['count'] = count;
//sync to cookie session equal to res.csflush(),make sure to call it before response
req.csflush();
res.send(count.toString());
});
app.listen(8124);
console.log('Server running at http://127.0.0.1:8124/');

Express and redis session keeps returning undefined

I've been having problems trying to access stored session values! Once I've set the values and try access them from a new route, I get undefined! So basically I've got a login (POST) and in that request I set the session data, and then I have a show user details (POST) where I try and access the session data I've just stored.
Setup
// Setup express and needed modules #############################################
var express = require('express'),
session = require('express-session'),
cookieParser = require('cookie-parser'),
redis = require("redis"),
redisStore = require('connect-redis')(session),
bodyParser = require('body-parser');
var client = redis.createClient(), //CREATE REDIS CLIENT
app = express();
// Setup app
app.use(cookieParser('yoursecretcode'));
app.use(session(
{
secret: 'x',
store: new redisStore({
port: 6379,
client: client
}),
saveUninitialized: true, // don't create session until something stored,
resave: false // don't save session if unmodified
}
));
app.use(bodyParser.urlencoded({ extended: true}));
app.use(bodyParser.json());
app.set('trust proxy', 1) // trust first proxy
So as you've seen my setup, you know I'm using express sessions and Redis. Below is where I'm setting the session values! If I print out the session values here it works, but then If I try and access the session data in another route it returns undefined.
Routes
I send a http post request and set the session data:
router.route('/login/').post(function(req, res) {
req.session.userId = req.body.uId;
req.session.name = req.body.uName;
// THIS PRINTS OUT IF I TRY AND ACCESS THE SESSION DATA HERE
console.log("THIS PRINTS OUT --> " + req.session.name);
});
So now that the session values have been set, I can go access them right, no, I get undefined each time I try and log them out.
router.route('/user/printoutuserdetails').post(function(req, res) {
// THESE RETURN UNDEFINED
console.log(req.session.userId);
console.log(req.session.uName);
console.log("THIS PRINTS OUT --> " + req.session.name);
});
Does anyone have any idea what's happening? I've tried everything and looked everywhere and can't seem to find a way to get it to work!
Solved:
The reason this wasn't was because you're not suppose to use sessions when using a RESTFUL api.

ExpressJS require() load order and Mongoose missing ModelSchema

I'm learning the MEAN stack and have found myself with a load order issue that doesn't seem to make sense.
The below code shows my server.js loading the routes file, which in turn pulls in the controller for a model, which in turn requires the model itself.
If I don't include a reference to the model from routes.js I get a MissingSchemeError when I startup the server. Why? Am I missing something regarding the loading of resources?
My understanding was that the exports for a file would be completely imported by the require() prior to attempting to run any code.
server.js
// modules =================================================
var express = require('express');
var bodyParser = require('body-parser');
var methodOverride = require('method-override');
var mongoose = require('mongoose');
var morgan = require('morgan');
var app = express();
// configuration ===========================================
// config files
var db = require('./config/db');
// set our port
var port = process.env.PORT || 8080;
// connect to our mongoDB database
mongoose.connect(db.url);
// get all data/stuff of the body (POST) parameters
// parse application/json
app.use(bodyParser.json());
// parse application/vnd.api+json as json
app.use(bodyParser.json({ type: 'application/vnd.api+json' }));
// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: true }));
// override with the X-HTTP-Method-Override header in the request. simulate DELETE/PUT
app.use(methodOverride('X-HTTP-Method-Override'));
// set the static files location /public/img will be /img for users
app.use(express.static(__dirname + '/public'));
// set morgan to log requests
app.use(morgan('dev'));
// routes ==================================================
require('./app/routes')(app);
routes.js
//this line is the problem. why is this needed?
var Customer = require('./models/customer'); // <--
var customers = require('./controllers/customer-server-controller');
module.exports = function(app) {
app.route('/api/customers')
.get(customers.list);
//.post(customer.create);
}
customer-server-controller.js
var mongoose = require('mongoose');
var Customer = mongoose.model('Customer');
/**
* List of Customers
*/
exports.list = function(req, res) {
Customer.find().sort('-created').exec(function(err, customers) {
if (err) {
return res.status(400).send({
message: "ERROR: " + err
});
} else {
res.jsonp(customers);
}
});
};
Got a good portion of the biolerplate from this tutorial on Scotch.io
I take it that you're missing the model from the tutorial
You should have this somewhere.
Create a models folder and add todo.js and add the following:
// define model =================
var Todo = mongoose.model('Todo', {
text : String
});
Your customer-server-controller.js doesn't require() the model file, it just tries to reference the model by asking Mongoose for it (Mongoose doesn't load the model file for you!):
var Customer = mongoose.model('Customer');
You need to require() the module file from your controller, otherwise the model isn't registered with Mongoose and you get the error that you got.

How can I set cookie in node js using express framework?

In my application, I need to set a cookie using the express framework. I have tried the following code but it's not setting the cookie.
var express = require('express'), http = require('http');
var app = express();
app.configure(function(){
app.use(express.cookieParser());
app.use(express.static(__dirname + '/public'));
app.use(function (req, res) {
var randomNumber=Math.random().toString();
randomNumber=randomNumber.substring(2,randomNumber.length);
res.cookie('cokkieName',randomNumber, { maxAge: 900000, httpOnly: true })
console.log('cookie have created successfully');
});
});
var server = http.createServer(app);
var io = require('socket.io').listen(server);
server.listen(5555);
The order in which you use middleware in Express matters: middleware declared earlier will get called first, and if it can handle a request, any middleware declared later will not get called.
If express.static is handling the request, you need to move your middleware up:
// need cookieParser middleware before we can do anything with cookies
app.use(express.cookieParser());
// set a cookie
app.use(function (req, res, next) {
// check if client sent cookie
var cookie = req.cookies.cookieName;
if (cookie === undefined) {
// no: set a new cookie
var randomNumber=Math.random().toString();
randomNumber=randomNumber.substring(2,randomNumber.length);
res.cookie('cookieName',randomNumber, { maxAge: 900000, httpOnly: true });
console.log('cookie created successfully');
} else {
// yes, cookie was already present
console.log('cookie exists', cookie);
}
next(); // <-- important!
});
// let static middleware do its job
app.use(express.static(__dirname + '/public'));
Also, middleware needs to either end a request (by sending back a response), or pass the request to the next middleware. In this case, I've done the latter by calling next() when the cookie has been set.
Update
As of now the cookie parser is a seperate npm package, so instead of using
app.use(express.cookieParser());
you need to install it separately using npm i cookie-parser and then use it as:
const cookieParser = require('cookie-parser');
app.use(cookieParser());
Set Cookie?
res.cookie('cookieName', 'cookieValue')
Read Cookie?
req.cookies
Demo
const express('express')
, cookieParser = require('cookie-parser'); // in order to read cookie sent from client
app.get('/', (req,res)=>{
// read cookies
console.log(req.cookies)
let options = {
maxAge: 1000 * 60 * 15, // would expire after 15 minutes
httpOnly: true, // The cookie only accessible by the web server
signed: true // Indicates if the cookie should be signed
}
// Set cookie
res.cookie('cookieName', 'cookieValue', options) // options is optional
res.send('')
})
Not exactly answering your question, but I came across your question, while looking for an answer to an issue that I had. Maybe it will help somebody else.
My issue was that cookies were set in server response, but were not saved by the browser.
The server response came back with cookies set:
Set-Cookie:my_cookie=HelloWorld; Path=/; Expires=Wed, 15 Mar 2017 15:59:59 GMT
This is how I solved it.
I used fetch in the client-side code. If you do not specify credentials: 'include' in the fetch options, cookies are neither sent to server nor saved by the browser, even though the server response sets cookies.
Example:
var headers = new Headers();
headers.append('Content-Type', 'application/json');
headers.append('Accept', 'application/json');
return fetch('/your/server_endpoint', {
method: 'POST',
mode: 'same-origin',
redirect: 'follow',
credentials: 'include', // Don't forget to specify this if you need cookies
headers: headers,
body: JSON.stringify({
first_name: 'John',
last_name: 'Doe'
})
})
Set a cookie:
res.cookie('cookie', 'monster')
https://expressjs.com/en/4x/api.html#res.cookie
Read a cookie:
(using cookie-parser middleware)
req.cookies['cookie']
https://expressjs.com/en/4x/api.html#req.cookies
Setting cookie in the express is easy
first install cookie-parser
npm install cookie-parser
using middleware
const cookieParser = require('cookie-parser');
app.use(cookieParser());
Set cookie know more
res.cookie('cookieName', '1', { expires: new Date(Date.now() + 900000), httpOnly: true })
Accessing that cookie know more
console.dir(req.cookies.cookieName)
Done!
setting a cookie can be done as such:
res.cookie('cookie name', 'cookie value', [options])
where cookie_name is the name(String) of the cookie you wish to set, for example - "token", and the cookie value is the value(String) you wish to store in the said cookie.
as far as options go, you can read more about them here:
https://expressjs.com/en/api.html
one example of an option is 'maxAge' which indicates how long a cookie is valid, this is used for example when assigning an authentication token and you wish to limit the time a user can stay logged in before having to re-login.
Reading a cookie can be done as such:
req.cookies['cookie name']
which will return the value of the cookie.
Isomorphic Read cookie helper:
function getCookieValue(cookieName = '', cookie = '') {
const matches = cookie.match(`(^|[^;]+)\\s*${cookieName}\\s*=\\s*([^;]+)`)
return matches ? matches.pop() : ''
}
// Node with express:
getCookieValue('cookieName', req.headers.cookie)
// Browser:
getCookieValue('cookieName', document.cookie)
Write in Node with express:
res.cookie('cookieName', 'cookieValue')
Write in the browser:
function setCookie(
cname,
cvalue,
exdays = 100 * 365 /* 100 days */
) {
const now = new Date()
const expireMs = exdays * 24 * 60 * 60 * 1000
now.setTime(now.getTime() + expireMs)
document.cookie = `${cname}=${cvalue};expires=${now.toUTCString()};path=/`
}
// Example of usage
setCookie('cookieName', 'cookieValue')
If you have a problem with setting multiple cookies for one request
Try this way:
res.setHeader('Set-Cookie', [
`accessToken=${accessToken}; HttpOnly; Path=/; Max-Age=${60 * 60}; Secure=True;`,
`refreshToken=${refreshToken}; HttpOnly; Path=/; Max-Age=${60 * 60 * 24 * 7 * 2}; Secure=True;`
]);

Resources