Cookies, Sessions, and Logins

Cookies

A cookie is a simple key/value pair that a website may stored with the user's browser. It is a per-user capability.

Have a look at what cookies are stored in your computer by viewing chrome://settings/cookies in Chrome.

In Express we can set cookies using the res.cookie function

In order to use the cookies, we also need the Express cookie-parser

npm install cookie-parser		
		

Here is a quick example which counts visits to a site on a per user basis:

var express = require('express');

// Require cookie-parser
var cookieParser = require('cookie-parser');

var app = express();

// Use the cookieParser middleware
app.use(cookieParser());

app.get('/', function (req, res) {
	// Log the cookies on the server side
	console.log(req.cookies);

	// Variable per request to keep track of visits
	var visits = 1;
	
	// If they have a "visits" cookie set, get the value and add 1 to it
	if (req.cookies.visits) {
		visits = Number(req.cookies.visits) + 1;
	}
	
	// Set the new or updated cookie
	res.cookie('visits', visits, {});
	
	// Send the info to the user
	res.send("You have visited this site " + visits + " times.");
});

app.listen(8080);		
		

Sessions

Sessions take the idea of cookies one step further by giving application developers the ability to set a unique ID per user in a cookie and then keeping a database of those IDs and associating other information along with that on the server.

In order to use sessions, you need the Express Session Middleware which you install with

npm install express-session		
		

Sessions by default are not persistent and the data get's destroyed when you restart the server. The easiest way around this is to use something like the NeDB Session Store

npm install nedb-session-store
		

Here is a simple example:

var express = require('express');
var app = express();
var session = require('express-session');
var nedbstore = require('nedb-session-store')(session);

// https://github.com/kelektiv/node-uuid
// npm install uuid
const uuidV1 = require('uuid/v1');

app.use(
	session(
		{
			secret: 'secret',
			cookie: {
				 maxAge: 365 * 24 * 60 * 60 * 1000   // e.g. 1 year
				},
			store: new nedbstore({
			 filename: 'sessions.db'
			})
		}
	)
);

app.get('/', function(req, res) {
  if (!req.session.userid) {
  	req.session.userid = uuidV1();
  }
  
  res.send('session user-id: ' + req.session.userid + '. ');
});

app.listen(8080);	
	

Mongo Data Store

Mongo Session Store
var express = require('express');
var app = express();
var session = require('express-session');
var MongoStore = require('connect-mongo')(session);

const uuidV1 = require('uuid/v1');

app.use(session({
    store: new MongoStore({
        url: 'mongodb://user12345:foobar@localhost/test-app'
    })
}));

app.get('/', function(req, res) {
  if (!req.session.userid) {
  	req.session.userid = uuidV1();
  }
  
  res.send('session user-id: ' + req.session.userid + '. ');
});

app.listen(8080);	

User Logins

Now that we have tackled cookies and user sessions, let's turn our attention to developing a user registration and login system.

The general idea is that we allow users to register, keep a table or collection of them in a database, and when they log in we create a session for them so that they stay logged in as they browse the site.

A basic registration screen would be a form asking for the details we need for each user (registration.ejs):

<html>
  <body>
	<form action="/register" method="POST">
		Choose Username: <input type="text" name="username"><br />
		Choose Password: <input type="password" name="password"><br />
		<input type="submit" name="submit" value="Submit"><br />
	</form>		
  </body>
</html>
		
this would post to a route on our server to save the user's information:
app.post('/register', function(req, res) {
	// We want to "hash" the password so that it isn't stored in clear text in the database
	var passwordHash = generateHash(req.body.password);

	// The information we want to store
	var registration = {
		"username": req.body.username,
		"password": passwordHash
	};

	// Insert into the database
	db.insert(registration);
	console.log("inserted " + registration);
	
	// Give the user an option of what to do next
	res.send("Registered Sign In" );
	
});		
		
In the above route, we are using a password hashing function that uses bcrypt. In particular it is using this node module: bcrypt-nodejs. Here is the hash and the comparison function that we'll need:
function generateHash(password) {
	return bcrypt.hashSync(password);
}

function compareHash(password, hash) {
    return bcrypt.compareSync(password, hash);
}		
		
After the user registration information is saved in the database we can offer a login form (login.ejs) and a corresponding route to check that their information is correct:
<html>
  <body>
	<form action="/login" method="POST">
		Username: <input type="text" name="username"><br />
		Password: <input type="password" name="password"><br />
		<input type="submit" name="submit" value="Submit"><br />
		<a href="/registration">Not registered?</a>			
	</form>		
  </body>
</html>		
		
The route:
// Post from login page
app.post('/login', function(req, res) {

	// Check username and password in database
	db.findOne({"username": req.body.username},
		function(err, doc) {
			if (doc != null) {
				
				// Found user, check password				
				if (compareHash(req.body.password, doc.password)) {				
					// Set the session variable
					req.session.username = doc.username;

					// Put some other data in there
					req.session.lastlogin = Date.now();

					res.redirect('/');
					
				} else {

					res.send("Invalid Try again");

				}
			} 
		}
	);
	

});		
		
The key to logging a user in is to create the session variable, in this case their username. This session variable can then be checked on any page they visit to make sure they are logged in and if they aren't send them to the login page:
// Main page
app.get('/', function(req, res) {
	console.log(req.session.username);

	if (!req.session.username) {
		res.render('login.ejs', {}); 
	} else {
		// Give them the main page
  		//res.send('session user-id: ' + req.session.userid + '. ');
		res.render('main.ejs', req.session);
	}
});
		
To log a user out, simply delete their session variable:
app.get('/logout', function(req, res) {
	delete req.session.username;
	res.redirect('/');
});		
		

Here is a full example:Express Login Example (Don't forget to make this use HTTPS)

Other Login Systems

Doing a full login system can be quite a bit of work. Fortunately, there are solutions that exist which make it easier.

On that is pretty popular is called Passport. Passport offers a "local" login system (called a "strategy") with similar functionality to what we have created above. It also offers a variety of other "strategies" for using the login functionality of single sign on services such as Twitter or Facebook.

Security

Implementing usernames/passwords this way via regular HTTP is very insecure. We should get started with HTTPS!