Session handling in any web application is very important and is a must-have feature, without it, we won’t be able to track users and it’s activity.
In this article, I am going to teach you how to handle Session in Node.js. We will use express as a framework and various other modules such as body-parser to handle form data.
At the time of writing the article, the latest version of Express is 4.16.4.
Table of Contents
What we are buiding
To demonstrate Session handling in Node, I have developed a basic Log-in and log-out System. In this User can log in by providing their email, and that email will be used for further Session tracking. Once the User log-out, Session will be destroyed and the User will be redirected to the home page.
Creating Node Project
Let’s create a new Node project. Create a new folder and switch to it using the terminal.
Run this command to create a new Node project.
This command will create a new package.json file. Let’s install the required dependency.
Once the dependencies are installed, we can proceed to code our app.
How to use Express Session ?
Before heading to actual code, i want to put few words about express-session module. to use this module, you must have to include express in your project. Like for all packages, we have to first include it.
const session = require('express-session');
const app = express();
After this, we have to initialize the session and we can do this by using the following.
Here ‘secret‘Â is used for cookie handling etc but we have to put some secret for managing Session in Express.
Now using ‘request‘ variable you can assign session to any variable. Just like we do in PHP using $_SESSIONÂ variable. for e.g
app.get('/',function(req,res){
sess=req.session;
/*
* Here we have assigned the 'session' to 'sess'.
* Now we can create any number of session variables we want.
* in PHP we do as $_SESSION['var name'].
* Here we do like this.
*/
sess.email; // equivalent to $_SESSION['email'] in PHP.
sess.username; // equivalent to $_SESSION['username'] in PHP.
});
After creating Session variables like sess.email , we can check whether this variable is set or not in other routers and can track the Session easily.
Tracking session in global variable won’t work with multiple users. This is just for the demonstration.
Project Structure
We are going to put all of Server side code in the server.js file. Front-end code will be placed inside the views folder.
Here is our Server-side code.
const session = require('express-session');
const bodyParser = require('body-parser');
const router = express.Router();
const app = express();
app.use(session({secret: 'ssshhhhh',saveUninitialized: true,resave: true}));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
app.use(express.static(__dirname + '/views'));
var sess; // global session, NOT recommended
router.get('/',(req,res) => {
sess = req.session;
if(sess.email) {
return res.redirect('/admin');
}
res.sendFile('index.html');
});
router.post('/login',(req,res) => {
sess = req.session;
sess.email = req.body.email;
res.end('done');
});
router.get('/admin',(req,res) => {
sess = req.session;
if(sess.email) {
res.write(`<h1>Hello ${sess.email} h1><br>`);
res.end('+'>Logout');
}
else {
res.write('
Please login first.
');res.end('+'>Login');
}
});
router.get('/logout',(req,res) => {
req.session.destroy((err) => {
if(err) {
return console.log(err);
}
res.redirect('/');
});
});
app.use('/', router);
app.listen(process.env.PORT || 3000,() => {
console.log(`App Started on PORT ${process.env.PORT || 3000}`);
});
In the code shown above, there are four routers. First, which render the home page, the second router is used for login operation. We are not doing any authentication here for the sake of simplicity.
The third router is used for the admin area where the user can only go if he/she is log-in. The fourth and the last router is for session destruction.
Each router checks whether the sess.emailvariable is set or not and that could be set only by logging in through front-end. Here is my HTML code which resides in views directory.
<head>
<title>Session Management in NodeJS using Node and Express</title>
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script>
$(document).ready(function(){
var email,pass;
$("#submit").click(function(){
email=$("#email").val();
pass=$("#password").val();
/*
* Perform some validation here.
*/
$.post("/login",{email:email,pass:pass},function(data){
if(data==='done') {
window.location.href="/admin";
}
});
});
});
</script>
</head>
<body>
<input type="text" size="40" placeholder="Type your email" id="email"><br />
<input type="password" size="40" placeholder="Type your password" id="password"><br />
<input type="button" value="Submit" id="submit">
</body>
</html>
In jQuery code, we are calling our Router ‘/login’Â and redirecting it to the ‘admin‘Â if log-in is successful, you can add validation to fields as per your requirement, for demo purpose i have not added any.
The Bug Alert!
As I have mentioned earlier, using a global variable for the session won’t work for multiple users. You will receive the same session information for all of the users.
So how do we solve this? By using a session store.
We save every session in the store so that one session will belong to one user only. I have explained and build session store using Redis in this article.
For a quick reference, he is how we can extend the code shown above using Redis as a session store.
First, you need to install Redis on your computer. Click here to learn how to install Redis.
Then, install these dependencies in your project.
Here is the codebase after upgrading it to support Redis.
* Manage Session in Node.js and ExpressJS
* Author: Shahid Shaikh
* Version : 0.0.2
*/
const express = require('express');
const session = require('express-session');
const bodyParser = require('body-parser');
const redis = require('redis');
const redisStore = require('connect-redis')(session);
const client = redis.createClient();
const router = express.Router();
const app = express();
app.use(session({
secret: 'ssshhhhh',
// create new redis store.
store: new redisStore({ host: 'localhost', port: 6379, client: client,ttl : 260}),
saveUninitialized: false,
resave: false
}));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
app.use(express.static(__dirname + '/views'));
router.get('/',(req,res) => {
let sess = req.session;
if(sess.email) {
return res.redirect('/admin');
}
res.sendFile('index.html');
});
router.post('/login',(req,res) => {
req.session.email = req.body.email;
res.end('done');
});
router.get('/admin',(req,res) => {
if(req.session.email) {
res.write(`<h1>Hello ${req.session.email} h1><br>`);
res.end('+'>Logout');
}
else {
res.write('
Please login first.
');res.end('+'>Login');
}
});
router.get('/logout',(req,res) => {
req.session.destroy((err) => {
if(err) {
return console.log(err);
}
res.redirect('/');
});
});
app.use('/', router);
app.listen(process.env.PORT || 3000,() => {
console.log(`App Started on PORT ${process.env.PORT || 3000}`);
});
If you notice in the code shown above, we have removed the global variable. We are using Redis to store our session instead. Try these multiple users and you should see a unique sessions for each user.
I highly recommend following this article for more detailed information.
How to run example code
Download code and extract the zip file. Open your command prompt or Terminal and switch to the directory. Install dependency first by using.
Then run code using
Visit localhost:3000 to view the app.
Conclusion:
Like I mentioned session is very important for any web application. Node.js allows us to create an HTTP server and HTTP is a stateless protocol. It stores no information about previous visit and Express solves this problem very beautifully.
Further reading
Nodejs tutorials
Node.js MySQL Tutorial
Programming a Voice Controlled Drone Using Node and ARDrone
Hi man !
Thanks for this great post ! I’ve got an issue with session managing, if you got some minuts could you help me please ?
I written some routes with app.get(). I’ve done an app.post for the login, and the mechanism works well (I’m going to auth my user by searching into a mongodb database). I then store his username in sess.username.
But when the user then navigate to the other routes, and I check sess.username it’s always null.
I’ve written sess = req.session; in the top of every routes dedicated code and then I checked the sess.username.
Oh, and sess is a global variable.
Do you see what is messing up ? Thanks in advance 🙂
Hi Alex,
Thanks for your posting your question.
Programmatically your approach is correct. Before i put my comment on it, could you please verify that your app.use(session(–rest params–)) uses this resave: true.
Thanks.
Thanks for replying Shahid 🙂
This value is true by default but I tried anyway to affect true to the resave option in session. I also tried to do a session.save function at login.
Maybe in the new version of express-session it is impossible to bind a value to the session objet ? thus i didn’t noticed something like this into the express-session doc …
I am facing the same problem.Did u got any solution ?/
have u tried changing app.use(session.-) i.i another version of session? Plz let me know!!
Alex, I realize this was a while back, but I’ll reply in hopes that it resolves someone stuck on a similiar problem. The reason your global variable sess is null is because its being reassigned for each request after it was initially set. The purpose of binding the session to the req variable is because its the only response-specific state being passed between the express middleware and routing.
Well, facing the same problem I think I got a solution : it seems like sess variable must be assigned to req.session in an other route before filling it via login route. Typically via the route( ‘/’ )
Nice Tut! Is there a better way to make {email, password, phone} more dynamic and match up destination structure?
Thanks!
Can you elaborate your question jeo?
Thanks for the nice tutorial.
Any idea how to handle/prevent concurrent session access ?
To handle concurrent session , you need to create unique Session ID and give it to client once the session is set so that next time until they logout / close browser they need to pass that unique ID in every request they made to server and you need to check it in every router.
Thanks for the reply.
Actually what i mean to ask was, can 2 treads simultaneously access session object and corrupt it’s state ? and how to prevent that.
I’m coming from servlet background, where session object is shared, so we synchronize it’s access.
You need to manually handle mutual exclusion of threads to particular session object.
Hi Shahid,
I am implementing the session handling for the first time. I am using NodeJs & express and Extjs for server and client side implementation respectively. The above reply of yours help me a lot. Thanks for that! However, I am struggling to send the sessionID fro client (ExtJs) back to server. Can you suggest me a way to do this? Also, if i am able to send that session ID somehow, What should i compare it with? req.sessionID?
If you want to send Anything to Nodejs server, you can do it using GET or POST HTTP method. Now as per your concern i am not sure why you want to send Session ID which you got from back-end to front-end again ?
Even I thought it was not needed to send the ID back to server and implemented it that way. But this reply of yours to “Arjun’s” query some days back, confused me slightly.
“To handle concurrent session , you need to create unique Session ID and give it to client once the session is set so that next time until they logout / close browser they need to pass that unique ID in every request they made to server and you need to check it in every router”
I am sorry if I asked something very obvious but as i have told u I am implementing this for the first time and so i want to make sure concurrent sessions are handled.
Do you have any example for concurrent session?
Hello!
How do I get to make this work with authFactory? Can’t seem to get any value for sess.email. It says it is undefined
app.get(‘/api/auth/login/session’,function(req,res){
sess = req.session;
if(sess.email)
{
console.log(sess.personid);
/*
results.personid = req.body.personid;
results.name = req.body..firstname;
results.email = req.body..email;
*/
}
else
{
console.log(‘sess email is undefined’);
}
});
Where the sess.email is set ? it should be set once before use.
Hey Shahid, I see where my problem is! I am not using php but express.js as my api. I am all new with angular but your tuts are amazing. I actually am doing a freelance project just from stuff I learned from you!
Thanks!!
I am glad to hear that Buju. Keep visiting.
Hello Shahid
I am using purely js for my api (express) but when user tries to login user gets kicked out.
.run(function ($rootScope, $location, authFactory) {
$rootScope.$on("$routeChangeStart", function (event, next, current) {
$rootScope.authenticated = false;
authFactory.GetSession('session').then(function (results) {
if (results.personid) {
$rootScope.authenticated = true;
$rootScope.personid = results.personid;
$rootScope.name = results.firstname;
$rootScope.email = results.email;
} else {
var nextUrl = next.$$route.originalPath;
if (nextUrl == '/signup' || nextUrl == '/login') {
} else {
$location.path("/login");
}
}
});
});
});
//serviceFactory
app.factory('authFactory', ['$http', function($http) {
//var urlBase = 'http://localhost:8001/api/auth/';
var urlBase = 'http://localhost:8001/api/auth/';
var authFactory = {};
authFactory.LogIn= function () {
return $http.post('http://localhost:8001/api/auth/login');
};
authFactory.LogOut= function (q) {
return $http.get('http://localhost:8001/api/auth/logout');
};
authFactory.GetSession = function (q) {
return $http.post('http://localhost:8001/api/auth/login/session/');
};
authFactory.Signup = function (q) {
return $http.post(urlBase + q);
};
authFactory.get = function (q) {
return $http.get(urlBase + q).then(function (results) {
return results.data;
});
};
return authFactory;
}]);
//api.js
app.post('/api/auth/login', function(req, res){
sess=req.session;
var email = req.body.email;
var password = req.body.password;
//In this we are assigning email to sess.email variable.
//email comes from HTML page.
sess.email = email;
sess.password = password;
connection.query('SELECT * FROM persons where email = "' + email + '" and password = "' + password + '"', req.params.id, function(err, rows, fields) {
if (err) {
console.error(err);
res.statusCode = 500;
res.send({
result: 'error',
err: err.code
});
}
res.send(rows);
});
});
Have you tried consoling those session variable.? Are they set or not.
Saving the session in a global variable surely cannot work when two users log in…
Every user who connect with your HTTP server gets a connection thread and Session is maintained for that thread. If you have code to demonstrate that its wrong then it would be awesome.
How will your setup work among multiple node applications? I’m assuming since you haven’t configured any shared storage (such as Redis or similar) for your session, that the default memory store is used. If that’s the case – and requests are handled by different applications (running on different processes) or perhaps (if on AWS) by different EC2 instances – then none of the above will work.
Yeah you are right. Above code was for handling session in simple web application. For shared instance we need storage like Redis or something to store session key. Will write tutorial on that. Thanks.
Thanks for the nice tutorial.it helps me to how use sessions in node.js..
Hi, Thanks for the great tutorial but I am facing an error. I am using express 4.0 and implementing session in routes/index.js
In the post when I do,
sess=req.session;
sess.usr=req.body.username;
I get error as – Cannot set property ‘usr’ of undefined
I have also tried doing –
var sess={usr:1,
st:2};
Still no luck.
Kindly help me.
Make sure sess is defined globally !
HI ,
Nice tutorial !
Can you please update to manage more then one user login at the same time .When ever a new request comes the old session data is replace by the new request .
code example
app.post(‘/validate’,function(req,res){
sess=req.session;
sess.username=req.body.username});
by the req.body.username i getting the username.
Yes i think that could be done by assigning sess variable to each HTTP connection. I’ll work on same.
Always Thanks for amazing posting!
Shahid can you provide me some ebooks on express js and MEAN Stack ???
hello,
Thanks for sharing administration with Node.js and expressjs sessiones
I have a question
It has the following
app.get(‘/logout’,function(req,res){
req.session.destroy(function(err){
if(err)console.log(err);
res.redirect(‘/’);
}
});
After removing the session is redirected to the root
After being at the root , if I make a back in the browser displays the previous page which should not happen
You know that makes this behavior?
What would be the solution?
I appreciate your time
note :
Before running app.get , I have a middleware where only verified if there is a session I make a next () ;
otherwise I make a redirect to the root
Hi,
Previous page is also the Router and if you are doing validation of session in each router or in Middle ware then this should not happen.
If session is inactive then redirect to home ( / ).
Mail me code if you can.
Thanks,
Shahid.
I’m facing a similar problem. Were you able to find a solution? If you did, could you please email it to me as well
Hi Shahid,
I have implemented passportjs for user authentication and authorization , I want to get the user details stored in session in angularjs(html not jade) frontend ?I don know how to move further Could you pls help me out ? I can see the browser cookie having the session userid but im not able to print the session details in index.js where I do my routing
module.exports = function(passport){
router.get(‘/’, isAuthenticated, function(req, res){
var user = req.session.user;
var a = req.user.username;
var b = req.user.password;
var c = req.user.emailid;
console.log(a); // not printing in the console
console.log(b); // not printing in the console
console.log(c); // not printing in the console
res.render(‘home’, { title: ‘User session Home’, user: req.user });
});
Hi Supraja,
Why don’t you use EJS parser which runs inside HTML. In that way you can pass data to HTML content too.
Sure Shahid wil try that out…
Shahid,
I added the below 2 lines in app.js
app.set(‘view engine’, ‘html’);
app.engine(‘html’, ejs.renderFile);
and tried fetching the json in html but cudn… Can you show a sample of how to get json in html ?
(OR) do i convert the .html into .ejs ?
try adding this
app.engine(‘html’, require(‘ejs’).renderFile);
make sure you have EJS installed.
Then on routes,
res.render(“home.html”,{ email : “shahid@codeforgeek.com”});
I think in your HTML should be like :
Hello <%= user %>
Please email your code.
Hi Shahid ,
I got the express session username in html without templating engine 🙂 Thank you so much for suggesting ejs. Now my issue is when i click logout btn the passport/express session isnt destroyed ,redirection to home doesn work and i also want to remove the username from the html.. im quite unclear abt logout routing whether im doing the right way or not . Your emailID pls !!
Hi supraja,
Its shahid@codeforgeek.com.
hi man.
i am from south korea.
i read well your tutorial and it helped me a lot. (sorry i do not english well)
can i ask one question?
long time ago, i read a article for session, in the article, ‘cookie-parser’ was necessary to use session. look following example code.
[psedo code]
app.use(cookieParser(~~~)); // cookieparser is located before session for working always.
app.use(session(~~~));
but in your tutorial, you didn’t use cookie-parser.
express or express session is changed about session mechanism?
No.
If you want to manipulate default cookie mechanism used by Express then you can use this package.
I have used it in my recent session tutorial.
hey Shahid !!
m trying to render a web page designed in polymer but unfortunately its is unable to inherit any of its data from polymer script if use normal express server . But i tried to do that with python it works good on that, can you please help me out to sort this issue. How can i run a normal polymer designed static page on Node sever other wise how to use Http server (in python : python -m http.server)
how to implement the same functionality using Angular js ?
as I’m working on MEAN
I don’t think its possible using front-end technologies. Sessions are stored in back ends.
MEAN is a Full-stack so it is inclusive of both back-end and front-end.
I know that very well but its programmer who made that stack and session has to be always controlled by Server not UI.
You need to view this tutorial to understand the working example.
Override the session value.
var express = require(‘express’);
var session = require(‘express-session’);
var sess;
step:1
router.post(“/login”, function(req, res) {
var email = “aaa@gmail.com”;
sess = req.session;
sess.email = email;
res.send({
data : sess
});
});
step:2
router.post(“/update”, function(req, res) {
var email = “bbb@gmail.com”;
sess = req.session;
sess.email = reqData.email;
res.send({
data : sess
});
});
step:3
router.get(“/check”, function(req, res) {
sess = req.session;
var email = sess.email;
console.log(email);
//Here display first value.(aaa@gmail.com)
//how can i get email value (bbb@gmail.com)?
});
How can I override the session value?
req.session.reload(function(err) {
// session updated
})
Really helpful. Thanks a lot!
Hi shahid, I tried your tutorial, i have app.js as my main file. I want to write the rest of the code in another file in controllers. But when i try to run it, it gives me an error “cannot read property of undefined”. Please help me out
Hi shahid,iam new to nodejs.I tried this tutorial it is working well but my problem is i made my own html page and i styled it with css,now i placed my stylesheet also in views folder and i gave that path in my html page but when i visit localhost:3000 only the plain html page is displaying,css is not supporting.so how can i display the page along with css.Please help me out.
vn, how the fuck you supposed this should work?
Like, author will leave all his tasks and start working on your problem? which is absolutely not relevant to this topic.
are you retarded or what??
thanks dude,its been amazing learning from you,I have finally learnt how to manage session using Node.js
Please help in maintaining the same session id throughout the session for a single user.
When I declared session id as global, same session id is retrieved for different users. How can this happen?
How to solve the problem?
You need to either use Redis as Session store OR use JWT instead of sessions.
Read the article here and here.
Hey shahid first of all thanks for this amazing tutorial. My problem is when my browser close then my session expire i m using sess.cookie.maxAge = false ; but it’s not work Thanks In advance.
Yeah, you need external session store for that.
Here is a tutorial on same.
Hi,
If Node Server stops due to some mongodb error or else, then session expires/out, so the user click any other route, the page will redirect to login…how can i fix this ?
Thanks
Thanks.
Hi
I have links:
res.write(“Pear” + “Pear”);
app.get(‘/addtocart/:pid’, function (req, res, next) {
sess = req.session;
if (sess.cart === undefined)
sess.cart = [];
var phoneId = req.params.pid;
console.log(phoneId);
//alert(phoneId);
sess.cart.push(phoneId);
console.log(“cart contains : “+sess.cart.length);
next();
//res.redirect(‘/products’);
});
this code adds to cart , but it redirects away
how to stay on products page?
regards
and thanks for good tutorial
Hi shahid,
I have written code for login , user details are kept in session , while another function doesnot reflectinng complete session
///Here is login function
exports.AdminLogin = function (req, res) {
sess = req.session;
sess.UserId = ‘someID’;
sess.Email = ’email’;
sess.isAuthenticated = true;
}
///Another function here session UserId and email not reflecting
exports.TimeSlotAdd = function (req, res) {
sess = req.session;
console.log(sess,’session’);
}
her in TimesSlot function i can get isAuthenticated but not UserID and Email
I have this code:
let session = null;
app.use((req, res, next) => {
session = req.session;
if (session.username) {
console.log(‘Has session username’);
} else {
console.log(‘Has no session username’);
res.redirect(‘/auth/login’);
}
console.log(new Date() + ‘|’ + req.url);
next();
});
routes.list(app); // list of routes, ex.: app.use(‘/’, homeController.index);
I’m getting this error:
_http_outgoing.js:356
throw new Error(‘Can\’t set headers after they are sent.’);
^
Error: Can’t set headers after they are sent.
at ServerResponse.OutgoingMessage.setHeader (_http_outgoing.js:356:11)
at ServerResponse.header (/home/julez/Workspace/js/topzeluj/node_modules/express/lib/response.js:767:10)
at ServerResponse.send (/home/julez/Workspace/js/topzeluj/node_modules/express/lib/response.js:170:12)
at done (/home/julez/Workspace/js/topzeluj/node_modules/express/lib/response.js:1004:10)
at load (/home/julez/Workspace/js/topzeluj/node_modules/twig/twig.js:7713:18)
at loadTemplateFn (/home/julez/Workspace/js/topzeluj/node_modules/twig/twig.js:5726:18)
at tryToString (fs.js:457:3)
at FSReqWrap.readFileAfterClose [as oncomplete] (fs.js:444:12)
Hello, i just want to tell you this is first explanation what i can understand easily and perfect.
Thanks for awesome guide man!
great great
can 2 different sessions be implemented for same client with different ttls?
Nope.
how to set expiration for session?
The time to live is the time session will remain active. You can increase or decrease that time to adjust your session time.
hello dear my file index.js session is working but these value is not getting in user.js file
sess.email is getting in index.js file but not getting these value in user.js file
Bhut ache shahid bhai lge rho..
nice tut 🙂
Thanks, bhai!
Nice for Node JS beginner.
Thanks Bro..,
The below is my code snippet
global.sess;
app.get(‘/’,function(req,res){
sess=req.session;
if(sess.email){
res.redirect(‘/admin’);
}
else{
res.render(‘index.html’);
}
});
app.post(‘/Test’,function(req,res){
sess = req.session;
//In this we are assigning email to sess.email variable.
//email comes from HTML page.
// sess.email={};
sess.email=req.body.email;
res.end(‘done’);
});
I am facing the error :
TypeError: Cannot set property ’email’ of undefined
Can you please help
TIA
Just replace the global.sess to var sess = null; and it should work fine.
Also, I strongly suggest you do not use this code in production, this is just for an explanation purpose.
In the production, you should use session store along with this code.
Here is the tutorial for the same.
Where is the session stored ?
Best regards
Great Explanation. Really enjoyed the article reading. I suggest you to write more and more tutorials like these.
when i close browser, session is gone, and require to login again. How to save the session?
Thanks for sharing Very Use ful Blog..