Networked Media Week 8

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

Logins

One way that cookies/sessions are typically used is to provide persistent logins to a site. Here is an 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 node-uuid
const uuidV1 = require('uuid/v1');

var bodyParser = require('body-parser');
var urlencodedParser = bodyParser.urlencoded({ extended: true }); // for parsing form data
app.use(urlencodedParser);

var allowedUsers = [
	{"username": "vanevery", "password": "vanevery"},
	{"username": "root", "password": "password"},
	{"username": "john", "password": "pass"}
];

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

// Main page
app.get('/', function(req, res) {
	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);
	}
});

app.get('/logout', function(req, res) {
	delete req.session.username;
	res.redirect('/');
});

// Post from login page
app.post('/login', function(req, res) {

	// Check username and password in database
	for (var i = 0; i < allowedUsers.length; i++) {
		if (allowedUsers[i].username == req.body.username &&
		    allowedUsers[i].password == req.body.password) {

			// Found user
			var userRecord = allowedUsers[i];

			// Set the session variable
			req.session.username = userRecord.username;

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


			break;	
		}
	}

	// Redirect back to main page
	res.redirect('/');

});

app.listen(8080);				
		
Here is the login.ejs view
<html>
  <head>
    <link rel="stylesheet" href="styles.css" type="text/css">
    <link rel="stylesheet" type="text/css" href="960_12_col.css" />
  </head>

  <body>
		<h1>MobilEyes Us</h1>
		
		<p>
			<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">
			</form>		
		</p>
  </body>
  </html>		
		
and here is main.ejs:
<html>
	<body>
		Welcome! <%= username %> you last logged in <%= lastlogin %>
		
		<br />
		<a href="/logout">Logout</a>
	</body>
</html>		
		

Security

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

HTTPS

HTTPS is a "secure" version of HTTP. It uses SSL or TLS to encrypt the contents of HTTP. Traditionally it has been used for banking and other more sensitive content, now it's use is widespread.

Normally to serve pages with HTTPS you need to get certificate that verifies your identity from a Certificate Authority.

At ITP we purchased a "wildcard" certificate which can be used on any server that uses the itp.io domain. We'll need to create a NET-ID.itp.io DNS entry for each of you. This means that if you install and use our certificate (which I'll email) correctly, you can serve your pages via https://NET-ID.itp.io without hassle.

Down the road, you might want to checkout Let's Encrypt, a new service which provides free certificates.

More about Public Key Cryptography: Public Key Cryptography: Diffie-Hellman Key Exchange

Using HTTPS with Express

Fortunately, node has a drop in replacement for the "http" library called "https". Here is a basic Express example:

var https = require('https');
var fs = require('fs'); // Using the filesystem module

var credentials = {
  key: fs.readFileSync('my-key.pem'),
  cert: fs.readFileSync('my-cert.pem')
};

// Start Normal Express Code
var express = require('express');
var app = express();

app.get('/', function(req, res) {
	res.send("Hello World!");
});
/////

var httpsServer = https.createServer(credentials, app);

// Default HTTPS Port
httpsServer.listen(443);