Sessions with Node.js and Express

Node.js, programming

I cannot believe how difficult it was to do something so simple. The bulk of the reason behind this, I believe, is the lack of documentation.

It always starts at App.js:

var express = require('express');
...
var app = express();
app.configure(function() {
...
app.use(express.bodyParser());
...
app.use(express.cookieParser('secret'));
...
app.use(express.session());
app.use(app.router);
...
});

...
app.get('/', routes.index);
app.get('/loginf', routes.loginf);
app.post('/login', routes.login);
app.get('/logout', routes.logout);

These set up the app to:

  • bodyParser: parse form submissions and put the parsed parameters into req.body
  • cookieParser: parse cookie values when present
  • session: session support
  • router: URL routing support
exports.index = function(req, res) {
  // If the session has a username, echo it to the view
  res.render('index', {username:req.session.username});
};

exports.loginf = function(req, res) {
  // render the login form
  res.render('loginf', {});
};

exports.login = function(req, res) {
  // extract the submitted form and record the user name
  // in the session
  var userName = req.body.username;
  var password = req.body.password;
  req.session.username = userName;
  res.redirect('/');
};

exports.logout = function(req, res) {
  // clear out the session
  req.session.destroy();
  res.redirect('/');
};

The index view (views/index.jade) either displays the current user name or offers a link to log in.

doctype 5
html
 body
  - if (typeof username != 'undefined') 
   div User #{username} 
   div 
    a(href='/logout') Log out
  - else
   div
    a(href='/loginf') Login please
html
 body
  table
   form(method='POST',action='/login')
    tr
     td
      div User Name
     td
      input(type='text',name='username')
    tr
     td
      div Password
     td
      input(type='text',name='password')
    tr
     td(colspan='2')
      input(type='submit',value='Log in')

Turns out the indentation matters in Jade, just like in Python. If A and B are in the same column, they are siblings. If B is indented further than and below A, then B is a child element of A.

Things yet to be figured out

All calls to render the ‘index’ view (or any other view that needs to know whether a user is logged in) currently needs to explicitly set the model’s “username” property. Is there an easier way? That is, can a Jade file access the session object?

Is there an interception/filter mechanism to reroute to the ‘loginf’ view if there is no “username” in the session, so that I don’t have to do this on every controller that requires a logged in user?

Turns out the answer is the various “middleware” components appended to “app” in app.js. This article describes it.