Azure Mobile Apps, NodeJS and Authentication

In a prior article, I introduced the new Azure Mobile Apps SDK, which is open sourced and available on GitHub. In that article, I produced a simple mobile API for accessing table information. It included a dynamic schema and offline sync capabilities.

That mobile app wasn’t actually that useful. In particular, anyone could write anything to my mobile app and I couldn’t control it. How does one control access to the mobile app?

Let’s start again, starting with a standard NodeJS application. Here is my starting application (and it’s located in bin/server.js):

var express = require('express'),
    morgan = require('morgan'),
    staticFiles = require('serve-static'),
    config = require('./config');

var webApp = express();

if (config.isDebugging()) {
  webApp.use(morgan('combined'));
}

webApp.use(staticFiles(config.webRoot, config.options.staticFiles));

webApp.get('/api/settings', function (req, res) {
  res.json(config.settings);
});

webApp.listen(config.webPort, function () {
  console.log('Listening on port ' + config.webPort);
});

This is my starter app, so nothing is peculiar here. If you’ve used ExpressJS at all, you will find this familiar territory. Now, let’s add an unauthenticated mobile app to it. In this case, I’m going to use the dev branch of azure-mobile-apps-node so that I get the latest code:

npm install --save azure/azure-mobile-apps-node#dev

I generally would recommend that you use the latest released version, but it isn’t released yet. It’s still in preview. As a result, things may change here.

To create the mobile WebAPI, I’m going to create a new javascript file called bin/zumo.js:

var azureMobileApp = require('azure-mobile-apps'),
    config = require('./config');

var zumo = azureMobileApp();

zumo.tables.use(function (req, res, next) {
  if (req.user) {
    req.azureMobile.user = req.user;
  }
  return next();
});

zumo.tables.import('./tables');

module.exports = exports = zumo;

The short version of what this code does is:

  1. Create a mobile SDK instance
  2. Handle the authentication object
  3. Import the tables definitions
  4. Export the whole instance for later

The third item there is easy – I have a directory bin/tables that contains a javascript file for the definition of each table. A basic table looks like this (from bin/tables/foo.js):

var azureMobileApps = require('azure-mobile-apps');

var table = azureMobileApps.table();

module.exports = exports = table;

This will create a REST endpoint for /tables/foo. The table name is taken from the filename of the javascript file.

I need to include the following in the bin/server.js to link in the mobile app:

var express = require('express'),
    morgan = require('morgan'),
    staticFiles = require('serve-static'),
    mobileApp = require('./zumo');
    config = require('./config');

var webApp = express();

if (config.isDebugging()) {
  webApp.use(morgan('combined'));
}

webApp.use(staticFiles(config.webRoot, config.options.staticFiles));

webApp.get('/api/settings', function (req, res) {
  res.json(config.settings);
});

webApp.use(mobileApp);

webApp.listen(config.webPort, function () {
  console.log('Listening on port ' + config.webPort);
});

You will have to provide a suitable config object. I’m using a javascript type module. Just look for config.* and ensure your object contains the definitions you need. You can actually run this code – it does the same as I provided last time. It’s just more modularized.

The second part of the zumo.js is interesting. It’s a piece of ExpressJS middleware attached to the /table endpoint. If some other code has created a req.user, then I assume authentication has been done. So I transfer that authentication to the SDK authentication.

If you were doing a mobile app and following the Azure Mobile Apps methodologies for authentication, then req.azureMobile.user would be configured to use the authentication gateway. Your mobile app would have a social authentication sign-in that used the authentication gateway. The authentication gateway would then return a token that would be decoded by the SDK.

However, I’m not doing a mobile app. I’m doing a web app and happen to want to share the token I produce. I am using a JSON web token (which you can decode on jwt.io) produced by Auth0 to secure my connection.

First off, I have a file (bin/jwt.js) that decodes the JWT I’m feeding in the REST API and produces a req.user object:

var jsonwebtoken = require('jsonwebtoken'),
    config = require('./config');

module.exports = exports = function jwt(req, res, next) {
  if (!req.headers.authorization) {
    return next();
  }

  var authParts = req.headers.authorization.split(' ');
  if (authParts[0].toLowerCase() !== 'bearer') {
    return next();
  }

  try {
    var options = {
      algorithm: 'HS256',
      audience: config.settings.auth.ClientID
    };
    var signature = new Buffer(config.authSecret, 'base64');
    var decoded = jsonwebtoken.verify(authParts[1], signature, options);

    if (!decoded.email) {
      return next();
    }

    decoded.id = decoded.email;
    req.user = decoded;
  } catch (err) {
    console.error('[jwt] error decoding token: ', err);
  }
  return next();
};

note that I set the ID to the email address. That’s my unique key for each user. That means that my JWT must contain a claim for the email address. If it doesn’t, then the req.user is not set.

Now I need to link THAT into my bin/server.js:

var express = require('express'),
    morgan = require('morgan'),
    staticFiles = require('serve-static'),
    jwt = require('./jwt'),
    mobileApp = require('./zumo');
    config = require('./config');

var webApp = express();

if (config.isDebugging()) {
  webApp.use(morgan('combined'));
}

webApp.use(staticFiles(config.webRoot, config.options.staticFiles));

webApp.get('/api/settings', function (req, res) {
  res.json(config.settings);
});

webApp.use(jwt);
webApp.use(mobileApp);

webApp.listen(config.webPort, function () {
  console.log('Listening on port ' + config.webPort);
});

Note that the use of the JWT decoder is BEFORE the use of the mobile app. Also, in zumo.js, the use that transfers the req.user into the SDK version is BEFORE the import of the tables. This ordering is important as middleware is executed in sequence.

Now all I need to do is tell the SDK that my table needs to be authorized. To do this, I set the authorise flag (note the British spelling – I approve of this) in the bin/tables/foo.js:

var azureMobileApps = require('azure-mobile-apps');

var table = azureMobileApps.table();
table.authorise = true;

module.exports = exports = table;

I suspect that the GA version of this library will allow the american spelling of authorise. Anglophiles can rejoice in the mean time.

My application has a mechanism of producing tokens (and I’ve covered this process many times in the past. Just click on the auth0 tag to the right). However, I’m going to be using Postman to check the API. First off, let’s do the unauthenticated version:

10062015-1

I get the appropriate 401 Unauthorized response and I can respond to that in my mobile or web app. To send an authenticated request, I submit an Authorization header with the token:

10062015-2

In this case, I’ve submitted the proper Authorization header and the API has accepted it. I can include logging within the request to see the decoded token (it’s in req.user or req.azureMobile.user). The id of the object is my email address from when I signed in.

Note that when I run the application, the Azure Mobile Apps SDK warns me that authentication is not configured. This is because the Gateway Authentication is not configured – we are bypassing that.

Custom Auth vs. Gateway Auth

So, why use custom auth and why use gateway auth? I like custom authentication like this because I develop “offline” and can provide my own token generator – after all, it’s just a JWT. I’m also using a third party authentication library – my web application uses Auth0 Lock which is a pop-up authentication window. No similar utility is provided by Azure.

If you have control over your mobile app and you want to just use the regular Facebook, Twitter, Google and Microsoft sign-in controls, then use the Azure gateway available in Azure Mobile Apps to get a mobile apps token. There are controls available for iOS, Android, Apache Cordova and Xamarin. You can also do a redirect to use the web.

If you want to use a third party authentication provider like Auth0, then use custom authentication. I tend to use Auth0 during development because of the popup Lock component plus the fact that Auth0 has development keys already registered for the four providers.

In either case, you get protected access to the tables configuration.