At my current company I am working on my first large-scale production backbone.js app and I couldn’t be happier. After using backbone.js for a few months I have caught the vision and I am becoming more and more proficient. But every once and a while I still run into problems I would consider basic, but I can’t seem to find much help on the interwebs. Authentication with backbone.js apps was one of those problems. So I am posting the solution I came up with in hopes it will benefit someone else, and hopefully will garner some feedback or potentially better ways to solve authentication with Backbone.js.

Starting Code Base

To start this tutorial, I will be using an already created backbone.js application called Backbone Directory, created by Christophe Coenraets who has some great tutorials and information about backbone on his blog. He has some mobile versions of the app in the code base as well, but we will be working in the “web” directory.

Project Overview

Backbone Directory uses the Slim PHP framework on the server to communicate with backbone, but the principles we will be going over are language agnostic. In addition, Slim is based on the Sinatra (Ruby) methodology which in turn translates to Express.js framework for Node.js (JavaScript), and Tornado (Python).

Setting Up (Very) Basic Server Side Authentication

To get this started, we need to setup the server side login functions, and also a way to protect API requests so no data goes to anyone that isn’t authenticated. First, let’s add a login function to the api/index.php in the web directory:

// file: api/index.php
session_start(); // Add this to the top of the file
/**
* Quick and dirty login function with hard coded credentials (admin/admin)
* This is just an example. Do not use this in a production environment
*/
function login() {
if(!empty($_POST['email']) && !empty($_POST['password'])) {
// normally you would load credentials from a database.
// This is just an example and is certainly not secure
if($_POST['email'] == 'admin' && $_POST['password'] == 'admin') {
$user = array("email"=>"admin", "firstName"=>"Clint", "lastName"=>"Berry", "role"=>"user");
$_SESSION['user'] = $user;
echo json_encode($user);
}
else {
echo '{"error":{"text":"You shall not pass..."}}';
}
}
else {
echo '{"error":{"text":"Username and Password are required."}}';
}
}

This is a very basic login function that is obviously not secure, but will do the job for us, since our focus is really on the backbone side of things. The key thing to note here, is that since we are using backbone, even the login function works as a JSON api request. We don’t generate any HTML, we simply send back JSON data with a user identity, or an error if something went wrong. Now we need to associate this function with a route in Slim, so add the following code under the other defined routes in index.php:

// file: api/index.php
// I add the login route as a post, since we will be posting the login form info
$app->post('/login', 'login');

Now we also need to make sure no data gets sent to anyone that isn’t authorized. So now we define an authorize function to check that a user has the right permissions to get the data:

// File: api/index.php
/**
* Authorise function, used as Slim Route Middlewear
*/
function authorize($role = "user") {
return function () use ( $role ) {
// Get the Slim framework object
$app = Slim::getInstance();
// First, check to see if the user is logged in at all
if(!empty($_SESSION['user'])) {
// Next, validate the role to make sure they can access the route
// We will assume admin role can access everything
if($_SESSION['user']['role'] == $role ||
$_SESSION['user']['role'] == 'admin') {
//User is logged in and has the correct permissions... Nice!
return true;
}
else {
// If a user is logged in, but doesn't have permissions, return 403
$app->halt(403, 'You shall not pass!');
}
}
else {
// If a user is not logged in at all, return a 401
$app->halt(401, 'You shall not pass!');
}
};
}

The authorize function uses some PHP closure Kung Fu, but the key is to return HTTP error codes to backbone. In our case we are going to return a 401 error (unauthorized) if a user is trying to access something they need to be logged in for, and a 403 (forbidden) if the user is logged in but doesn’t have enough privs to get the data he wants.

This view is pretty straight forward. It renders the login template, and put a click event handler on the login button. The event handler fires the login function when the button is clicked and sends an ajax request to our php login function. If an error comes back, we put it in the error div and show that div.

Telling Backbone How to Handle 401 & 403 Errors (ajaxSetup)

Now here comes the kicker. We need backbone/jquery to catch any requests that return a 401 or 403 error and handle those requests appropriately. The method I have used to do this is to call the jquery function ajaxSetup which allows us to watch for certain status codes and to handle them appropriately.

The Final Word (and source code)

That is it! You should now have a password protected REST API for BackboneJS. I have posted the project to github (here), so feel free to check out the code and see it in action. Currently, you will need PHP/Apache with MySQL setup and the database imported. I am working on a Vagrant file for the project so you will be able to see it in action without setting up your own server.