Node + Stormpath

Since the release of our new node.js Stormpath Library I’ve been itching to get my hands dirty and build something.

So — let’s build something together :)

NOTE: If you’d like to skip the tutorial below and jump straight into the code, I’ve put this app on Github for your viewing pleasure: https://github.com/stormpath/stormpath-express-sample

What We’re Building

I thought a great way to test out the new Stormpath node libraries would be to build a simple website that allows you to do a few things:

  • Create a new account (register) with email and password.
  • Log into your new account (login) with email and password.
  • Display a dashboard page once you’ve logged in, that is only accessible to users with an account.
  • Redirect unauthenticated users who try to access the dashboard back to the login page.
  • Allow a logged in user to log out of their account (logout).

Pretty simple — but that should at least allow us to play around with the new tooling!

In the end, things should look like this:

Node App Home
Node App Register
Node App Dashboard

Sound good? I thought so!

Intro to Stormpath

If you aren’t already familiar with Stormpath, it’s an API service that allows you to create, edit, and securely store your application’s user accounts and user account data. Stormpath makes it easy to do stuff like:

  • User registration and login.
  • Account verification via email.
  • Password reset via email.
  • Social login.
  • And a bunch of other cool stuff you probably don’t like coding!

So — why should you use Stormpath?

Well, quite simply, we make building user accounts a lot easier, more secure, and more scalable than what you’re probably used to.

Using Stormpath not only allows you to easily build your application out, but it also allows you to scale your site to support millions of users without changing your code, or even needing a database!

So, let’s dive in.

If you don’t already have a Stormpath account and application, you’ll need to create one now — you can do so here: https://api.stormpath.com/register

The rest of this article will assume you have a Stormpath account and API key pair.

The Tools

To build this simple app, we’ll be using

If you’re not familiar with express, you should check it out! express is an awesome web framework for node.js which makes building full-fledged web applications a lot simpler.

One of the most important pieces of express is the middleware layer (powered by connect). This middleware allows you to tap into HTTP requests before they reach your view code, allowing you to do cool stuff like authenticate users, among other things.

Next up is passport. Passport is a generic library for handling user authentication in node web apps. It allows you to abstract away some of the technical details related to handling web session and authentication. We’ll be using this in combination with the official passport-stormpath backend to log users in and out of our new web app.

Lastly, we’ll also be using the official Stormpath node library to register new users (essentially we’ll be sending Stormpath’s API service a POST request when a new user creates an account, this way the user will be stored securely on Stormpath’s servers).

Getting Started

So, now that we’ve covered what this web app will be doing, what it’ll look like, and what we’ll use to build it: let’s get this going!

The first thing you need to do is install node.js (if you don’t already have it installed).

Next, let’s install express.js by running:

$ npm install -g express-generator

The express-generator module allows you to easily generate a project skeleton to get started with (yey!).

Now that we have express, let’s create our basic project directory:

$ express --css stylus stormpath-express-sample

   create : stormpath-express-sample
   create : stormpath-express-sample/package.json
   create : stormpath-express-sample/app.js
   create : stormpath-express-sample/public
   create : stormpath-express-sample/public/javascripts
   create : stormpath-express-sample/public/images
   create : stormpath-express-sample/public/stylesheets
   create : stormpath-express-sample/public/stylesheets/style.styl
   create : stormpath-express-sample/routes
   create : stormpath-express-sample/routes/index.js
   create : stormpath-express-sample/routes/users.js
   create : stormpath-express-sample/views
   create : stormpath-express-sample/views/index.jade
   create : stormpath-express-sample/views/layout.jade
   create : stormpath-express-sample/views/error.jade
   create : stormpath-express-sample/bin
   create : stormpath-express-sample/bin/www

   install dependencies:
     $ cd stormpath-express-sample && npm install

   run the app:
     $ DEBUG=my-application ./bin/www

Then, of course, you’ll want to go into your project directory and install all
of the basic dependencies:

$ cd stormpath-express-sample
$ npm install

And that’s it for the basic configuration!

Configuration

Now that we have our skeleton application ready (thanks, express!), let’s change our project name in the package.json file.

Open up package.json and change the name field so it says "stormpath-express-sample" instead of "application-name". This will make any errors we have easier to debug later on.

Install Required Modules

The next thing we’ll want to do is install all of the required modules we’re going to be using.

You can install them all by running the following command:

$ npm install passport passport-stormpath express-session connect-flash stormpath --save

This command will install:

NOTE: The --save flag instructs node to install the packages, and then add them as dependencies to your project’s package.json file. This way, if you want to bootstrap this project at a later time, you can do so easily by just running npm install.

Set Environment Variables

Now that we’ve installed all the required modules, let’s configure our environment variables.

We’re going to be using environment variables to tell our web app what credentials / secrets to use when running our app.

You’ll want to create a .env file in the root of your project with the following contents:

export STORMPATH_API_KEY_ID=xxx
export STORMPATH_API_KEY_SECRET=xxx
export STORMPATH_APP_HREF=xxx
export EXPRESS_SECRET=some_random_string

Obviously, you’ll need to replace these values with the appropriate values! The Stormpath settings (API_KEY_ID, API_KEY_SECRET, and APP_HREF) will be used to tell the app how to communicate with Stormpath. The EXPRESS_SECRET variable is used to make session management secure (this should be a long string of random characters).

If you haven’t already created a Stormpath application, you’ll want to go into the Stormpath admin console and create a new Application called stormpath-express-sample. Once you’ve created this application, you should see an Application REST URL in the web interface — use this URL as the value for your STORMPATH_APP_HREF environment variable.

Once you’ve got the environment variables defined in your .env file, all you need to do is use them:

$ source .env

The source command will run the .env file, setting the environment variables in your current terminal session.

Configure Middleware

The next thing we need to do is open up the app.js file and import our dependencies. You’ll want to make the top of your app.js file look like the below:

var express = require('express');
var path = require('path');
var favicon = require('static-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');

// These are the new imports we're adding:
var passport = require('passport');
var StormpathStrategy = require('passport-stormpath');
var session = require('express-session');
var flash = require('connect-flash');

Now that we have our dependencies imported, let’s configure them!

In app.js, you’ll want to add the following:

var app = express();

// Here is what we're adding:
var strategy = new StormpathStrategy();
passport.use(strategy);
passport.serializeUser(strategy.serializeUser);
passport.deserializeUser(strategy.deserializeUser);

Next, we need to configure some of our middleware in app.js:

app.use(favicon());
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded());
app.use(cookieParser());
app.use(require('stylus').middleware(path.join(__dirname, 'public')));
app.use(express.static(path.join(__dirname, 'public')));

// Stuff we're adding:
app.use(session({
  secret: process.env.EXPRESS_SECRET,
  key: 'sid',
  cookie: {secure: false},
}));
app.use(passport.initialize());
app.use(passport.session());
app.use(flash());

This just tells express to activate our middleware components.

I learned how to do all of the above by reading through the project documentation for the following libraries (it’s nothing special!):

Now we’re ready to move onto the good stuff: our routes.

Writing the Routes

Writing routes is where the real action happens.

We’re going to define several routes:

  • A / route which just displays a simple home page.
  • A /register route which renders a registration page. This route will need to
    accept both GET and POST requests.
  • A /login route which will allow existing users to log in. This route will
    need to accept both GET and POST requests as well.
  • A /logout route which will log users out of their account.
  • A /dashboard route which will display a dashboard page for logged in users.

To keep things orderly, let’s create two separate route files.

First, open up the routes/index.js file and replace its contents with the following:

var express = require('express');
var router = express.Router();


// Render the home page.
router.get('/', function(req, res) {
  res.render('index', {title: 'Home', user: req.user});
});


// Render the dashboard page.
router.get('/dashboard', function (req, res) {
  if (!req.user || req.user.status !== 'ENABLED') {
    return res.redirect('/login');
  }

  res.render('dashboard', {title: 'Dashboard', user: req.user});
});

module.exports = router;

This index.js route file holds all of the main website routes (anything not auth related).

Next, create a new file named routes/auth.js and add the following code:

var express = require('express');
var router = express.Router();
var passport = require('passport');
var stormpath = require('stormpath');


// Render the registration page.
router.get('/register', function(req, res) {
  res.render('register', {title: 'Register', error: req.flash('error')[0]});
});


// Register a new user to Stormpath.
router.post('/register', function(req, res) {

  var username = req.body.username;
  var password = req.body.password;

  // Grab user fields.
  if (!username || !password) {
    return res.render('register', {title: 'Register', error: 'Email and password required.'});
  }

  // Initialize our Stormpath client.
  var apiKey = new stormpath.ApiKey(
    process.env['STORMPATH_API_KEY_ID'],
    process.env['STORMPATH_API_KEY_SECRET']
  );
  var spClient = new stormpath.Client({ apiKey: apiKey });

  // Grab our app, then attempt to create this user's account.
  var app = spClient.getApplication(process.env['STORMPATH_APP_HREF'], function(err, app) {
    if (err) throw err;

    app.createAccount({
      givenName: 'John',
      surname: 'Smith',
      username: username,
      email: username,
      password: password,
    }, function (err, createdAccount) {
      if (err) {
        return res.render('register', {title: 'Register', error: err.userMessage});
      } else {
        passport.authenticate('stormpath')(req, res, function () {
          return res.redirect('/dashboard');
        });
      }
    });
  });

});


// Render the login page.
router.get('/login', function(req, res) {
  res.render('login', {title: 'Login', error: req.flash('error')[0]});
});


// Authenticate a user.
router.post(
  '/login',
  passport.authenticate(
    'stormpath',
    {
      successRedirect: '/dashboard',
      failureRedirect: '/login',
      failureFlash: 'Invalid email or password.',
    }
  )
);


// Logout the user, then redirect to the home page.
router.get('/logout', function(req, res) {
  req.logout();
  res.redirect('/');
});


module.exports = router;

This auth.js route file contains all the routes that handle user-specific stuff: registration, login, and logout.

Now that we’ve created our routes, we have to also plug them into the main app.js file so they’ll be used by express.

First, remove the existing routes near the top of your app.js file:

app.use(passport.session());
app.use(flash());

// Remove these two lines.
var routes = require('./routes/index');
var users = require('./routes/users');

Next, add in the following two lines to replace the ones you just removed:

var index_routes = require('./routes/index');
var auth_routes = require('./routes/auth');

After importing the routes, we’ll also need to bind them to express’ URL routing mechanism:

app.use(passport.session());
app.use(flash());

// Specify the routes here.
app.use('/', index_routes);
app.use('/', auth_routes);

Then, delete the existing routes that were there — the lines you’ll want to remove are the following:

// Remove these two lines:
app.use('/', routes);
app.use('/users', users);

And with the changes above made — we’ve just successfully finished writing our routes! In the next section, we’ll dive into understanding the routes, and explain why things work the way they do.

Understanding the Routes

Now that we’ve defined our routes, let’s see how they actually work!

The Home Page Route

Let’s start by looking at the home page route:

// Render the home page.
router.get('/', function(req, res) {
  res.render('index', {title: 'Home', user: req.user});
});

The home page route isn’t doing much other than rendering a template (which we have yet to create!), and passing in some variable values.

The important thing to note here is the title and user values. We’ll use the title variable in our template to generate a nice HTML title for the page. We’ll also use the user variable to tell us whether or not the person viewing the home page is a user or not.

If the person viewing the page IS a user, then instead of displaying a Login button on the website, we’ll just display a link to the Dashboard page.

The req.user variable is automatically populated for us by passport. It will either be undefined, or a JSON object of this user’s account.

The Dashboard Route

The dashboard route is also quite simple:

// Render the dashboard page.
router.get('/dashboard', function (req, res) {
  if (!req.user || req.user.status !== 'ENABLED') {
    return res.redirect('/login');
  }

  res.render('dashboard', {
    title: 'Dashboard',
    user: req.user,
    }
  );
});

The first thing we’ll do here is check to see if the person viewing this page is a user, and then, if their account is enabled or not (Stormpath allows you to have users that disabled).

If the person viewing our dashboard page isn’t a valid user, we’ll redirect the user to the login page.

If the person IS a valid user, we’ll render our dashboard page (simple — right?).

The Registration Route

Now we’ll dive into the authentication routes. We’ll start by looking at our registration route — which is responsible for signing up new users.

// Render the registration page.
router.get('/register', function(req, res) {
  res.render('register', {title: 'Register', error: req.flash('error')[0]});
});


// Register a new user to Stormpath.
router.post('/register', function(req, res) {

  var username = req.body.username;
  var password = req.body.password;

  // Grab user fields.
  if (!username || !password) {
    return res.render('register', {title: 'Register', error: 'Email and password required.'});
  }

  // Initialize our Stormpath client.
  var apiKey = new stormpath.ApiKey(
    process.env['STORMPATH_API_KEY_ID'],
    process.env['STORMPATH_API_KEY_SECRET']
  );
  var spClient = new stormpath.Client({ apiKey: apiKey });

  // Grab our app, then attempt to create this user's account.
  var app = spClient.getApplication(process.env['STORMPATH_APP_HREF'], function(err, app) {
    if (err) throw err;

    app.createAccount({
      givenName: 'John',
      surname: 'Smith',
      username: username,
      email: username,
      password: password,
    }, function (err, createdAccount) {
      if (err) {
        return res.render('register', {title: 'Register', error: err.userMessage});
      } else {
        passport.authenticate('stormpath')(req, res, function () {
          return res.redirect('/dashboard');
        });
      }
    });
  });

});

The first bit just renders the registration page for GET requests.

The second bit is where things get interesting.

Firstly, we’re checking for a username and password field from the HTTP form. This is what the user will be submitting to us when they create a new account. (The username field is actually an email address, but I’ll explain this in more detail later.)

Next, we’ll re-render the registration page (with an error message) if either the username or password fields are missing.

After that’s out of the way, we need to initialize the Stormpath client. This involves using our API key credentials to make a new client, and then fetching our Stormpath application (since we’ll need to create this new user account inside of our application namespace).

Once we’ve fetched our Stormpath application, we’ll then create a new user account using the createAccount method. Since Stormpath requires (at minimum):

  • givenName
  • surname
  • email
  • and password

fields — but we only want to store email / password — I’m just setting the givenName and surname values to 'John' and 'Smith'.

NOTE: If the user account creation fails, we’ll render the registration page and pass in an appropriate error message from Stormpath. This will automatically handle problems like users attempting to register with an email that already exists.

If everything goes smoothly, we’ll use the passport.js library to log this new user in (creating a session, transparently), then redirect the user to the dashboard page.

The Login Route

// Render the login page.
router.get('/login', function(req, res) {
  res.render('login', {title: 'Login', error: req.flash('error')[0]});
});


// Authenticate a user.
router.post(
  '/login',
  passport.authenticate(
    'stormpath',
    {
      successRedirect: '/dashboard',
      failureRedirect: '/login',
      failureFlash: 'Invalid email or password.',
    }
  )
);

The login routes (shown above) are responsible for logging existing users back into the site. The GET route only renders the login page, along with an optional error message to display if a user enters invalid credentials.

NOTE: The req.flash('error')[0] you see is provided by the connect-flash library. If a login fails, the passport.js library will embed a tiny little ‘error’ message in a cookie, which is what the req.flash('error')[0] call then retrieves.

The POST request is completely offloaded to the passport.js library. passport provides the authenticate method which will transparently check the username and password form fields against the Stormpath API, and take care of login automatically.

If the login is successful, passport will redirect the user to the dashboard page — otherwise, it’ll re-render the login page once more, along with a friendly error message.

The Logout Route

// Logout the user, then redirect to the home page.
router.get('/logout', function(req, res) {
  req.logout();
  res.redirect('/');
});

The logout route (above) will log the user out of their account, destroying their session cookies.

The passport library automatically adds a logout method onto the req object, which makes it easy to log a user out of their account.

Once we’ve logged the user out, we simply redirect them back to the home page.

Writing the Templates

The last big thing we have to do is define our templates. The templates are the HTML layer that gets presented to users.

Let’s get started!

Create a Layout

The first thing we’ll want to do is create a layout.jade template. By default, our new express app is using the jade templating language (check it out if you haven’t, it’s quite cool).

Here’s our views/layout.jade template:

doctype html
html
  head
    meta(charset='utf-8')
    meta(content='IE=edge', http-equiv='X-UA-Compatible')
    meta(content='width=device-width, initial-scale=1', name='viewport')
    title= 'Express-Stormpath (sample) | ' + title
    link(href='/css/bootstrap.min.css', rel='stylesheet')
    link(href='/css/style.css', rel='stylesheet')
    <!--[if lt IE 9 ]>
    <script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
    <script src="https://oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"></script>
    <![endif]-->
  body
    .container
      .header
        ul.nav.nav-pills.pull-right
          li
            a(href='/') Home
          if user
            li
              a(href='/dashboard') Dashbaord
            li
              a(href='/logout') Logout
          else
            li
              a(href='/login') Login
        h3.text-muted Flask-Express
      block body
    script(src='https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js')
    script(src='/js/bootstrap.min.js')

The main thing our fancy new layout template does is provide a basic HTML page layout that all our other pages will use.

The line which reads block body will be overridden by our other templates.

The most important bit to take note of here is the nav menu:

if user
  li
    a(href='/dashboard') Dashbaord
  li
    a(href='/logout') Logout
else
  li
    a(href='/login') Login
      block body

We’re using a simple conditional here to check to see whether or not a user is logged in or not (if user), and changing the links the visitor sees accordingly. This ensures that if a user is logged in, and on the homepage — they won’t see a ‘Login’ button displayed in the navbar.

The Home Page Template

Place the following code into: views/index.jade:

extends layout

block body

  #welcome.jumbotron
    h1 Welcome to Stormpath-Express
    p.lead.
      <br/>
      <br/>
      Welcome to this gloriously simple <a href="https://github.com/stormpath/stormpath-express-sample">Stormpath</a>
      sample app!
    ul
      li First, take a look through this very basic site.
      li.
        Then, check out this project's source code
        <a href="https://github.com/stormpath/stormpath-express-sample">on GitHub</a>.
      li Lastly, integrate Stormpath into your own sites!
    <br/>
    <br/>
    h2 What this Sample App Demonstrates
    br
    p.
      This simple app demonstrates how easy it is to register, login, and
      securely authenticate users on your website using Stormpath.
    p.
      Aren't a Stormpath user yet?
      <a href="https://stormpath.com">Go signup now!</a>
    p.
      <b>NOTE</b>:
      This app will NOT work until you have gone through the bootstrapping
      instructions found in this project's <code>README.md</code> file. For more
      information, please follow the guide on this project's
      <a href="https://github.com/stormpath/stormpath-express-sample">GitHub page</a>.
    p.bigbutton
      a.bigbutton.btn.btn-lg.btn-danger(href='/register', role='button') Register

This is our home page template. All it does is render some static information for users, so there isn’t much to go into here.

Since our layout.jade template is already handling our user-smart nav bar, we don’t need to do anything special :)

The Registration Template

Place the following code into views/register.jade:

extends layout

block body

  .register
    .row
      .col-lg-6.col-lg-offset-3
        form.bs-example.form-horizontal(method='post', action='')
          fieldset
            legend Create a New Account
            if error
              .alert.alert-dismissable.alert-danger.register-fail
                button.close(data-dismiss='alert', type='button') &times;
                p.
                  #{error}
            p.
              Registering for this site will create a new user account for you
              via <a href="https://stormpath.com">Stormpath</a>, then log you in
              automatically.
            .alert.alert-dismissable.alert-info
              button.close(data-dismiss='alert', type='button') &times;
              strong NOTE:&nbsp;
              Your password must be between 8 and 100 characters, and must
              contain lowercase letters, uppercase letters, and numbers.
            .form-group
              label.col-lg-4.control-label(for='username') Email
              .col-lg-4
                input#username.form-control(name='username', type='email', placeholder='Email', autofocus)
            .form-group
              label.col-lg-4.control-label(for='password') Password
              .col-lg-4
                input#password.form-control(name='password', type='password', placeholder='Password')
            .form-group
              .col-lg-10.col-lg-offset-4
                button.btn.btn-primary(type='submit') Register
        h2 A Note About Stormpath Security
        p.
          In a real environment, you should <b>only deploy your application</b>
          behind SSL / TLS to avoid having user credentials sent in plain text
          over the network.
        p.
          Stormpath user creation is incredibly secure, is not susceptible to
          any known vulnerabilities (MITM, hashing issues, replace attacks,
          etc.), and provides you with a number of options to improve security
          (including buil-in email verification, among other things).  We will
          not verify your account by email now, but this can be easily enabled.
        p.last-p.
          Stormpath can also be configured to allow for weaker (or force
          stronger) passwords, so it can fit into any application workflow.

This page handles user registration.

Take a close look at the form — we’re specifying two fields for the user to input: email and password. Take a look at the email input box, however:

input#username.form-control(name='username', type='email', placeholder='Email', autofocus)

Although we’re collecting a user’s email address here, we’re setting the HTML name attribute to the value username. This is to make passport happy.

Passport expects username and password form elements, so that’s what we’ll use (despite the fact that we’re signing a user with just email / password).

We’ll also render an error message to the user (if there is one). This will be called if the registration fails for some reason, displaying a user-friendly error message.

The Login Template

Start by putting the following code into views/login.jade:

extends layout

block body

  .login
    .row
      .col-lg-6.col-lg-offset-3
        form.bs-example.form-horizontal(method='post', action='')
          fieldset
            legend Login
            if error
              .alert.alert-dismissable.alert-danger.login-fail
                button.close(type='button', data-dismiss='alert') &times;
                p.
                  #{error}
            p.last-p.
              Once you enter your credentials and hit the Login button below,
              your credentials will be securely sent to
              <a href="https://stormpath.com">Stormpath</a> and verified.  If
              your credentials are valid, you'll be logged in using a secure
              session -- otherwise, you'll get a user friendly error message.
            .form-group
              label.col-lg-4.control-label(for='username') Email
              .col-lg-4
                input#username.form-control(type='email', name='username', placeholder='Email', autofocus)
            .form-group
              label.col-lg-4.control-label(for='password') Password
              .col-lg-4
                input#password.form-control(type='password', name='password', placeholder='Password')
            .form-group
              .col-lg-10.col-lg-offset-4
                button.btn.btn-primary(type='submit') Login

The login template works almost exactly like the registration template we talked about previously. Although we ask users to log in with an email and password, we secretly name the email input field username to make passport happy.

Other than that, things work as you would expect if there is an error, we’ll display a user-friendly error message.

The Dashboard Template

Put the following code into views/dashboard.jade:

extends layout

block body

  .dashboard
    .row
      .col-lg-12
        .jumbotron
          h1 Dashboard
          br
          br
          p Welcome to your user dashboard!
          p.
            This page displays some of your user information using Jade
            templates.
          p.
            If you click the Logout link in the navbar at the top of this page,
            you'll be logged out of your account and redirected back to the main
            page of this site.
          p.
            Your user account information is being securely stored using
            passport sessions, and Stormpath as the authentication backend.
          br
          br

This is probably the simplest of all the templates — it just renders some static content.

This page is only accessible to logged in users.

Static Assets

The last thing we need to do before we can run our awesome new project is drop in our static assets. This mainly involves copying over Twitter Bootstrap (I’m not a good designer, OK!).

You can run the following commands to download the necessary files locally (into your public directory):

$ mkdir -p public/{css,js}
$ wget https://raw.githubusercontent.com/stormpath/stormpath-express-sample/master/public/css/bootstrap.min.css --directory-prefix public/css
$ wget https://raw.githubusercontent.com/stormpath/stormpath-express-sample/master/public/css/style.css --directory-prefix public/css
$ wget https://raw.githubusercontent.com/stormpath/stormpath-express-sample/master/public/js/bootstrap.min.js --directory-prefix public/js

Let’s Run This Thing

Now that we’ve gone through the entire project from start to finish, let’s run this thing!

From the command line, you should be able to run npm start at the root of your project, to launch a local web server on port 3000:

$ npm start

> stormpath-express-sample@0.0.1 start
> /Users/rdegges/stormpath-express-sample
> node ./bin/www

Now, open your browser and visit http://localhost:3000. Assuming everything is working well, you should be able to register a new account on the site, visit the dashboard, logout, and log back in again — with no problems.

Here’s how things should look:

Lastly — all this code is available on Github here: https://github.com/stormpath/stormpath-express-sample

Final Thoughts

Firstly, if you made it to the bottom of this post: thanks! Hopefully you enjoyed building this node app along with me!

With that said, in the future, we’re planning on expanding our Stormpath support for both node.js and passport.js to make integration even simpler.

Among other things, we’d like to:

  • Make registering users a one liner (instead of requiring custom development work).
  • Make asserting user permissions simple and effortless (making it easy to handle user groups and permissions at a fine-grained level).
  • Make our passport.js middleware more magical by having it automatically patch user data into templates for rendering.
  • Make our passport.js strategy support caching clusters (or either Redis or Memcached) — this way you’ll be able to speed up user sessions quite a bit by avoiding round-trips to the Stormpath REST API.

Got anything else you think would be cool to see added? Please drop us a line! We’d love to hear from you :)

Best,

-Randall