Running BabelJS/ES2015 Apps in Azure App Service

BabelJS is a really cool in-line transpiler. You can use it as a ‘require-hook’ to make your Node.js apps use the full ES6 syntax without the v8 javascript interpreter issues around ES6 support. For instance, I have a server.js file that looks like this:

require('babel-register');
require('./app');

My app.js file contains regular ES6 code, like this:

import express from 'express';
import process from 'process';
import staticFiles from 'serve-static';

let app = express();
app.use(staticFiles('public', { index: 'index.html' }));
app.listen(process.env.PORT || 3000);

I’ve also got a public directory and an index.html file inside the public directory for display. Finally, I need a .babelrc file:

{
    "presets": [ "es2015" ]
}

Assuming I’ve installed all the right packages:

npm install --save babel-register babel-preset-es2015 express serve-static

This will run and I’ll be able to browse to http://localhost:3000 and get my index page. It just works. Which is a great thing. Now, let’s transfer it up to the cloud. Azure App Service to be precise.

To do this, I logged onto the Azure Portal, created a new Web App and set up Continuous Deployment to read my site from the GitHub repository. When it deployed, I got a successful deployment. However, when I browsed to my site, I got a failure. The failure in the logs was this:

Mon Dec 28 2015 22:36:55 GMT+0000 (Coordinated Universal Time): Unaught exception: Error: ENOENT: no such file or directory, open 'D:\local\UserProfile\.babel.json'
    at Error (native)
    at Object.fs.openSync (fs.js:584:18)
    at Object.fs.writeFileSync (fs.js:1224:33)
    at save (D:\home\site\wwwroot\node_modules\babel-register\lib\cache.js:45:19)
    at nextTickCallbackWith0Args (node.js:433:9)
    at process._tickCallback (node.js:362:13)
    at Function.Module.runMain (module.js:432:11)
    at startup (node.js:141:18)
    at node.js:980:3

I don’t even have this .babel.json file, so what’s wrong? By default, BabelJS will save a cache file in your user profile. This is fine if you are running in the context of a user account – user accounts generally have a home directory or user profile.

BabelJS saves the JSON Cache in the following places:

  • BABEL_CACHE_PATH
  • USERPROFILE
  • HOMEDRIVE + HOMEPATH
  • HOME

You can also set BABEL_DISABLE_CACHE=1 to disable the generation of this file. Since the existence of this file improves startup times (and Azure does restart your site from time to time), you probably want to keep the file.

These are all environment variables. In Azure, USERPROFILE points to a directory that does not exist – there is no user in Azure. My opinion is that it should point to the temporary directory or not be set. Azure has a temporary directory at D:\local\Temp. We can force BabelJS to write to the temporary directory by specify an App Setting. To do this:

  1. Log onto the Azure Portal and select your Web App.
  2. Click on Settings, then Application Settings (under GENERAL).
  3. Scroll down to the bottom of the App settings section.
  4. In an empty box, for key, enter BABEL_CACHE_PATH and for value, enter D:\local\Temp\babel.json
  5. Click on Save.

You application may need a restart. Once restarted, browse to your site again and see it work properly. With this app setting, your site will work for both local development and within the Azure cloud.

Logging to Splunk with Winston

I have to admit, I’ve still got a soft spot for Splunk in my heart. I spent several years developing apps there and it is still my go-to logging platform. Recently, I’ve been playing with ExpressJS and using Winston as my logger of choice, together with express-winston to hook the two pieces up. My projects inevitably start with this:

var express = require('express'),
    winston = require('winston'),
    expressLogger = require('express-winston');

var app = express();

app.use(expressLogger.logger({
    transports: [
        new winston.transports.Console()
    ],
    level: 'debug'
}));

// Do other setup here
app.listen(process.env.PORT || 3000);

This is all well and good, but what about Splunk? My prior version of this wrote the log to a file and then Splunk would consume the file. However, I’m operating inside of Azure App Service these days and my Splunk instance is operating on a different machine – it’s a virtual machine inside of Azure. So what am I to do?

Splunk recognized this and so they produced a high-performance HTTP event collector. This is a REST endpoint that allows you to submit data as long as you have a token. I’m not going to explain how to get a token (Splunk does a really good job of that). However, I need to handle the other side of things – the Winston transport.

Fortunately, Winston has a highly extensible transport system and I’ve done just that. You can download the module from npmjs.org or get it from my GitHub repository.

So, how do you use it? It doesn’t require Express, but I’m going to alter my prior example to show how easy it is. Note the highlighted lines:

var express = require('express'),
    winston = require('winston'),
    SplunkStreamEvent = require('winston-splunk-httplogger'),
    expressLogger = require('express-winston');

var app = express();

var splunkSettings = {
    host: 'my-splunk-host',
    token: 'MY-DATAINPUT-TOKEN'
};

app.use(expressLogger.logger({
    transports: [
        new winston.transports.Console(),
        new SplunkStreamEvent({ splunk: splunkSettings });
    ],
    level: 'debug'
}));

// Do other setup here
app.listen(process.env.PORT || 3000);

Block-by-block:

  1. Line 3 brings in the library – standard Node module management here
  2. Lines 8-11 define the options for the splunk-logging library
  3. Line 16 adds the transport to winston for logging

It’s as simple as that. There is one proviso. Underneath, it uses the excellent splunk-logging library. Winston expects that you send off each event individually. It doesn’t really stream events. As a result, setting any of the options in such a way that batching occurs will result in weird errors. That’s because Winston is expecting a callback for each event and the splunk-logging library doesn’t call the callback unless it actually writes to the channel. I haven’t done any high capacity tests to see what happens when batching does occur, so I’d avoid that for now.

If you find any bugs or wish to ask a question, please let me know through the GitHub Repository.

Node, MVC Controllers and ECMAScript 2015

Long time readers of my blog will remember that I previously covered Node and MVC applications in a short tutorial series. At that point, I wrote the controllers and loader in ECMAScript 5.1. The code to load the controllers was this:

  fs.readdirSync("./controllers").forEach(function (file) {
    if (file.substr(-3) === ".js") {
      console.info("Loading Controller " + file);
      var base = "/" + path.basename(file, ".js");
      var route = require("./controllers/" + file);
      app.use(base, route);
    }
  });

The typical controller looked like this:

"use strict";

var express = require("express"),
    path = require("path"),
    config = require("../config.json"),
    extend = require("extend");

var router = express.Router(), // eslint-disable-line new-cap
    controller = path.basename(__filename, ".js"),
    loginRoute = config.loginRoute || "/account/login";

/**
 * Set of default properties for the rendering engine
 */
function defaultProperties(req) {
  return {
    title: "Unknown",   // Default title in case the developer doesn't set one
    user: req.user
  };
}

/**
 * Render an appropriate view
 */
function view(req, res, viewName, locals) {
  res.render(controller + "/" + viewName + ".html",
    extend({}, defaultProperties(req), locals));
}

/**
 * GET /{controller=Home}/index
 */
function index(req, res) {
  if (!req.isAuthenticated()) {
    res.redirect(loginRoute);
    return;
  }
  view(req, res, "index", { title: "Home" });
}

// Per-route functionality
router.get("/index", index);

// Default route is to GET index
router.get("/", index);

module.exports = router;

That’s a lot of boilerplate code and it’s completely unreadable for mere mortals. I am working on learning ECMAScript 2015 in depth and I thought I would re-visit this topic. Could I make my controller modules into classes and simplify the whole controller configuration?

Step 1: The New Controller Loader

Since my controllers are going to be classes, I knew I was going to need to adjust the loader. My aim here is just to load the controller classes; not to get the perfect class loader. Here is my code:

// MVC Controllers
var controllerList = {};
fs.readdirSync(path.join(__dirname, "controllers")).forEach(function (file) {
	if (file.substr(-3) === ".js") {
		var basePath = path.basename(file, ".js");
		var Controller = require(`./controllers/${file}`);
		controllerList[basePath] = new Controller(basePath);
		app.use(`/${basePath}`, controllerList[basePath].router);
	}
});

This code loops through every single JavaScript file in the controllers directory. For each one, it constructs a basePath. If the controller is called home.js, then the basePath becomes “home”. I then load the javascript file using a standard “require” statement. Since it’s a class, I create a new object passing in the basePath. I expect that object to expose a router parameter and I use that to link in the router to the basePath. I construct the path using an ES6 template string.

Step 2: The Controller – First Pass

One of the concepts I am pretty religious about is this: Don’t over-complicate the solution early. Get it working, then see if you can do something to make the solution simpler, easy to test, read better, more efficient or whatever you want to do. Here is my first controller:

var express = require("express"),
	extend = require("extend");

export default class HomeController {
	constructor(basePath) {
		this.basePath = basePath;
		this.router = express.Router(); //eslint-disable-line new-cap

		// Route definitions for this controller
		this.router.get("/", (req, res) => { this.index(req, res); });
		this.router.get("/index", (req, res) => { this.index(req, res); });
	}

	renderView(response, viewName, localData = {}) {
		let viewPath = this.basePath + "/" + viewName;
		let defaultData = {
			title: "~~~Unknown~~~"
		};
		let data = extend(defaultData, localData);
		response.render(viewPath, data);
	}

	// GET /home/index (or just /home)
	index(request, response) {
		this.renderView(response, "index");
	}
}

One of the things you will note is that this actually has a lot in common with the ECMAScript5 version of the same controller – it’s just in class form. My module exports the controller class by default. That means I can import it with whatever name I want. The constructor stores the base path that it is passed and creates a new router. The constructor also constructs the routes available in the controller. It uses ES6 fat arrows to preserve the “this” variable.

The renderView method combines a dataset with a view and renders a view. Note I’m using ES6 default parameters and the block-level “let” statement – more ES6 features in use.

Finally, I have a method that actually handles a route. Really, the only unique things for this controller are the index() method that handles a route and the route definition in the constructor.

Step 3: Simplify the Code

This controller class actually works, but I can see a bunch of duplicated code. In the constructor, the basePath and router will always be done this way. I’m allowing the underlying system access to the router variable – definitely not what I want. I want the router to be read-only after creation. Also, the renderView() method is going to be boiler plate code – I want to abstract that away. My simplifying thought here is this: let’s create a Controller class with all the common code in it. We can then extend the Controller class to create the HomeController and only include the “differences”. Here is my new Controller.js file:

var express = require("express"),
	extend = require("extend");

export class Controller {
	constructor(basePath) {
		this.prvBase = basePath;
		this.prvRouter = express.Router(); //eslint-disable-line new-cap
	}

	renderView(response, viewName, localData = {}) {
		let viewPath = this.prvBase + "/" + viewName;
		let defaultData = {
			title: "~~~Unknown~~~"
		};
		let data = extend(defaultData, localData);
		response.render(viewPath, data);
	}

	get basePath() {
		return this.prvBase;
	}

	get router() {
		return this.prvRouter;
	}
}

A lot of this code comes from the original home.js code. I’ve converted the basePath and router variables into ES6 getters so that I can make them read-only (assuming one uses the published API). Now, what does an implementation of a controller look like? Let’s look at the new home.js:

import {Controller} from "../mvc/Controller";

export default class HomeController extends Controller {
	constructor(basePath) {
		super(basePath);

		// Route definitions for this controller
		this.router.get("/", (req, res) => { this.index(req, res); });
		this.router.get("/index", (req, res) => { this.index(req, res); });
	}

	index(request, response) {
		this.renderView(response, "index");
	}
}

This is getting much closer to where I want to be. The super() call is for running the constructor of the class I am extending, thus setting up the common code. I still have to define the routes within the constructor, but I don’t have any boiler-plate code.

What else would make this controller object awesome? ECMAScript 7 is defining a concept called decorators. With ES7 decorators, I could theoretically do something like this:

export default class HomeController extends Controller {
    @HttpGet([ "/", "/index" ])
    index(request, response) {
        this.renderView(response, "index");
    }
}

Of course, ES2015 (also known as ES6) is just out and I don’t expect ES7 to be ratified for a number of years, so there is no guarantee that anyone will support ES7 decorators. You can check out the compatibility chart at Kangax. Note that only Babel supports ES7 decorators right now.

I’m going to delve into decorators in another blog post. For now, this mechanism is great for developing an MVC application without the need of libraries beyond the standard ExpressJS.

Creating a Secure (TLS) Node.js MVC Application

Recently, I investigated node.js and came up with a pretty solid pattern or starting project for an MVC style application. There was one problem – it used an insecure transport (normal plaintext HTTP). The world is moving towards universal encryption and I contend that this should be the default case even when developing. You can use a variety of packet sniffing technologies when you are developing in plain text that are simply not available or severely restricted when you transition to a secure communications channel. So develop with a secure server.

That doesn’t mean you have to go spend money on secure signed certificates. You can use “self-signed” certificates to do the work. There are plenty of articles on how to produce self-signed certificates for Ubuntu, CentOS and Mac. This article shows you how to produce self-signed certificates suitable for a node application with Windows.

Creating an SSL Certificate

Most instructions for creating and using an SSL certificate in node require you to produce two .pem files – one key and one certificate. This is great if you have access to OpenSSL. That tool makes it really easy to produce the appropriate files. It’s not so easy on Windows. However, it is easy to produce a .pfx file – a secure bundle of all the bits you need.

First off, start up the IIS Manager and open Server Certificates:

blog-0706-1

Click on Create Self-Signed Certificate:

blog-0706-2

Enter a friendly name, for example “Development Node Certificate” and click on OK:

blog-0706-3

Now you can click on the certificate you just created and then click on Export:

blog-0706-4

Save the .pfx file somewhere. Make sure you specify a strong password and note it down – it goes in your configuration.

blog-0706-5

Writing a Node/Express HTTPS Server

The second part to this process is to create a Node/Express HTTPS Server. I started in Visual Studio by using the Basic Node.js Express 4 Application. First off, create a file config.json in the root of the project. Mine looks like this:

{
  "port": 3000,
  "host": "localhost",
  "https": {
    "pfx": "C:/Users/photo/Certificates/node-dev.pfx",
    "passphrase": "my really secure password that no-one will guess",
    "ciphers": "ECDHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA256:AES128-GCM-SHA256:RC4:HIGH:!MD5:!aNULL",
    "honorCipherOrder": true
  }
}

In secure servers, you need to specify both the host and the port. The interesting stuff is in the https block. The pfx field is the path to my PFX file and the passphrase is the secure password that I created when exporting the certificate.

The next two lines are important for anyone who is running a production secure server. The first line tells the server what ciphers to accept. I don’t accept insecure ciphers and this line gets updated when new threats invalidate a cipher. The second honorCipherOrder tells the server to insist on more secure ciphers over less secure ciphers. This is a key component to protecting against SSL BEAST attacks.

Next, edit ./bin/www – this is the bootstrap code for starting the server. Replace the contents with the following:

#!/usr/bin/env node

var fs = require('fs'),
	https = require('https'),
	app = require('../app'),
	config = require('../config.json');

app.set('port', process.env.PORT || config.port || 3000);

console.log("Loading PFX File");
var pfxFile = config.https.pfx;
config.https.pfx = fs.readFileSync(pfxFile);

console.log("Starting Server");
var server = https.createServer(config.https, app).listen(app.get('port'), config.host);

The standard version uses the built-in code in Express to do the listening. This version creates a HTTPS server context explicitly. Also, I turn the pfx path into a buffer containing the PFX data prior to calling the createServer. Given that I’ve abstracted all the configuration to config.json, this can be considered boilerplate.

Finally, generally I want the browser to start up when I run the project. That doesn’t happen automatically. Right-click on the project and select Properties. Then set the Launch URL to https://localhost:1337/ replacing the port with whatever port is in the Node.js port box:

blog-0706-6

You should be able to run this and check how the connection is configured. In Chrome, right-click on the page and select Page Info. In Internet Explorer, right click and select Properties:

blog-0706-7

Note the TLS v1.2 – you want to see at least that. If you see SSLv2, SSLv3 or any TLS prior to v1.2, then your page is not as secure as you think.

One final note – and it should be obvious. NEVER check in your pfx file. If your config file contains your password, then don’t check that in either.

To get around the password problem, I tend to use a process.env.SSLPASSPHRASE over-ride. For example:

var passphrase = process.env.SSLPASSPHRASE || config.https.passphrase || "";
config.https.passphrase = passphrase;

Hopefully, this assists those node developers who happen to like Windows too!

Web API – Node Style

In the last four articles I’ve been doing a study of what it takes to do a node app. For those who are starting here, I had a list of requirements:

  1. I need to be able to run a small web server
  2. I need to be able to handle templated views with server-side code
  3. I need to be able to do social authentication
  4. I need to be able to use an MVC architecture
  5. I need to be able to provide a Web API
  6. I need to be able to publish a node app to Azure
  7. I need to be able to edit node applications in Visual Studio 2015

Todays article is all about the Web API. If you remember, I am developing a Dungeons and Dragons Character Sheet app as a side project. One of the things you need to do is to list and look up spells for your character. So I need a spell reference. To do this, I’m going to add two routes to my project: /api/spells to list all spells and /api/spells/number to get information on a specific spell. This is, after all, just to demonstrate what is required to do an unauthenticated Web API in Node.

I’ve got some spell data in data/spells.json – it’s just a JSON file with a bunch of fields. I could just as easily push this into a database (like SQL Server or MongoDB), but it’s small enough that I can load it at runtime. The json file itself is an array with objects – one for each spell. Each spell has an _id field that uniquely identifies the object.

Don’t like spells? Well, you can replace “spells” with products, books, companies, or whatever you desire.

To start the API, I’ve introduced an API controller in controllers/api.js:

/*eslint-env node */

"use strict";

var express = require("express"),
    passport = require("passport"),
    path = require("path"),
    config = require("../config.json"),
    spells = require("../data/spells.json");

var router = express.Router(), // eslint-disable-line new-cap
    controller = path.basename(__filename, ".js");

// Set up the Web API Here

module.exports = router;

This is mostly boilerplate code – the same code runs inside the home controller and the account controller. It uses the same routing mechanism, so I can set up my routes just the same way. In fact, the only real difference is that I need to return JSON data rather than HTML.

The /api/spells route is easy, but the /api/spells/number route requires a little explaining. Let’s get the list function out the way first:

function get_all_spells(req, res) {
  res.status(200).json(spells);
}

router.get("/spells", get_all_spells);

There is no view in the Web API world. Instead, Express knows how to send JSON directly. In this case, I set the HTTP Response code to 200 (which means success) and then dump out the spells list that I loaded earlier.

Now, back to that special case. Here is the route:

router.get("/spells/:id", get_one_spell);

Here I’m using a standard notation for a route – whatever route segment comes after the colon will be placed into the req.params object and named the same thing. In this case, I am going to get a req.params.id as a string in my function call:

function get_one_spell(req, res) {
  // Figure out what ID we are actually looking for.  If it is non-numeric,
  // then throw a "Not Found" error back to the user.
  try {
    if (req.params && req.params.id) {
      var id = parseInt(req.params.id);
    } else {
      res.status(404).json({ error: "Spell ID must be numeric" });
      return;
    }
  } catch (e) {
    res.status(404).json({ error: "Spell ID is always a number" });
    return;
  }

  // Find the spell by ID - returns empty array if not found
  var spell = spells.filter(function(o) {
    return o._id === id;
  });
  if (spell === undefined || spell.length === 0) {
    res.status(404).json({ error: "Spell ID Not Found" });
  } else {
    res.status(200).json(spell[0]);
  }
}

Step 1 in this method is to convert the thing we get into a number. However, you should never trust the user. The ID may be non-numeric, missing, a space, special characters – pretty much anything. So the code needs to handle those cases. The try-catch block converts what the user gives me to an integer and returns an error to the user in all other cases.

Now that I have an integer, I can try to find the spell. I’m using Array.filter() here. If node was running ECMAScript 6 then I could use Array.find(), but Node is ECMAScript 5 right now. Array.filter() returns an empty array if it doesn’t find any matches. It could be more than one match, but that is improbable if we properly format the data.

If the returned array is undefined or the length is zero, then I tell the user that the spell is not found, otherwise return success (HTTP Response Code 200) and dump the JSON object.

Right now, this is unauthenticated, so I can just test the API using Postman (available on Chrome) or another Web REST API tool:

blog-code-0523-1

Authentication

The Web API I’ve developed is unauthenticated right now – anyone can consume it. I probably want it authenticated. I can do this two ways – firstly, I can use the req.isAuthenticated() to adjust the output. For instance, I may want to provide everyone with a set of data, but provide a minimal set of data to everyone and extra data to authenticated users. I can do this in the get_all_spells() method like this:

function get_all_spells(req, res) {
  // If the user is not authenticated, only show spells on level
  // 1 or the cantrips.
  if (!req.isAuthenticated()) {
    var spell_list = spells.filter(function(o) {
      return (o.Level === "Cantrip" || o.Level === 1);
    });
    res.status(200).json(spell_list);
    return;
  } else {
    // User is authenticated - show all the spells
    res.status(200).json(spells);
  }
}

Simulating Authentication in Postman

One of the biggest hurdles for me was this. How do I test my authenticated API code? For that matter, what does an Unauthenticated vs. Authenticated Web API look like? To check this out, I took a look at an authentication request via node in Fiddler.

When I browse to my home page the first time, this is what I get:

blog-code-0523-2

The request for / results in a 302 Redirect to /home, which results in a 302 Redirect to /account/login which then returns the view and the view requires a couple of CSS pages. Clicking on Twitter gets me the following:

blog-code-0523-3

I’m using Auth0, so clicking on the Twitter Icon really loads my Auth0 page, which then eventually loads Twitter. Once I’ve done the twitter authentication, I’m back at the /account/external-callback URI before redirecting back to the home. Let’s take a look at that final request for the home page:

blog-code-0523-4

Note the connect.sid cookie – this is what authenticates the session. I need to include that in any authenticated session.

Let’s say I don’t want the use to be able to use the /api/spells/:id unless authenticated. There is no consensus on how to implement authentication in Web APIs:

  1. Return a 302 “Redirect” to the login page
  2. Return a 511 “Network Authentication Required” with a list of authentication providers
  3. Accept an Authorization header with the information and return 301 “Unauthenticated” if it isn’t provided

If a user tries to use the /api/spells/:id route unauthenticated, I’m going to return a 302 Redirect to /account/login. My code now looks like this:

function get_one_spell(req, res) {
  // If the user is not authenticated, tell them to authenticate
  if (!req.isAuthenticated()) {
    res.redirect("/account/login");
    return;
  }

  // Rest of the get_one_spell method
}

When I run this through the process in Postman, I can see the following:

blog-code-0523-5

This isn’t very friendly. When I’m using an API, I don’t want to see HTML that is meant for a human. Let’s instead look at option #2 (the 511 Network Authentication Required version):

function get_login_api() {
  var connections = config.passport.auth0.connections || [],
      r = {}, 
      buildurl = function(provider) {
        var server = config.server.uri || "http://localhost:3000";
        var url = "https://" + config.passport.auth0.domain + "/authorize" +
          "?response_type=code&scope=openid%20profile" +
          "&client_id=" + config.passport.auth0.clientid +
          "&redirect_uri=" + server + "/" + controller + "/external-callback" +
          "&connection=" + provider;
        return url;
      };
      
  for (var i = 0; i < connections.length; i++) {
    r[connections[i].replace("-","_")] = buildurl(connections[i]);
  }
  
  return r;
}

function get_one_spell(req, res) {
  // If the user is not authenticated, tell them to authenticate
  if (!req.isAuthenticated()) {
    res.status(511).json(get_login_api());
    return;
  }
  
  // Rest of the get_one_spell method
}

The get_login_api() converts the configuration we have set up to be an object that we can serialize to JSON. When I run the request in Postman, I get the following:

blog-code-0523-6

I’ve obfuscated the client ID. However, you can see that this returns JSON I can work with. A list of the providers and their respective links is provided. As part of a richer login scheme – for instance, with a Single Page Application (SPA) – I can see this working.

Which one you provide is up to you. I like the 511 response code when you are using social logins with a SPA. I’ve seen the 301 Unauthenticated version implemented a few times as well. You have a lot more flexibility, of course, if your interface is only being used by your application.

As always, my code is up on my GitHub Repository.

MVC Architecture – Node Style

In the last three articles I’ve been doing a study of what it takes to do a node app. For those who are starting here, I had a list of requirements:

  1. I need to be able to run a small web server
  2. I need to be able to handle templated views with server-side code
  3. I need to be able to do social authentication
  4. I need to be able to use an MVC architecture
  5. I need to be able to provide a Web API
  6. I need to be able to publish a node app to Azure
  7. I need to be able to edit node applications in Visual Studio 2015

I didn’t like the way I was writing code in the first three articles. It looked a little hacky. I wanted to get a clear separation of concerns – something the MVC pattern provides and something I am using in my ASP.NET vNext projects. I finally got there, but it was a lot of code.

Let’s start with the package.json – I needed a bunch more libraries to do MVC than I was using before. Here is my new package.json file:

{
  "name": "basic-webapp",
  "version": "0.0.1",
  "description": "A Basic View-Controller Web Application",
  "main": "server.js",
  "private": true,
  "scripts": {
    "start": "node server.js"
  },
  "repository": {
    "type": "git",
    "url": "https://github.com/adrianhall/node-stuff"
  },
  "author": "Adrian Hall ",
  "contributors": [
    {
      "name": "Adrian Hall",
      "email": "adrian@shellmonger.com"
    }
  ],
  "license": "MIT",
  "bugs": {
    "url": "https://github.com/adrianhall/node-stuff/issues"
  },
  "homepage": "https://github.com/adrianhall/node-stuff",
  "dependencies": {
    "body-parser": "^1.12.3",
    "cookie-parser": "^1.3.4",
    "ejs": "^2.3.1",
    "express": "^4.12.3",
    "express-partials": "^0.3.0",
    "express-session": "^1.11.1",
    "extend": "^2.0.1",
    "method-override": "^2.3.2",
    "passport": "^0.2.1",
    "passport-auth0": "^0.2.1",
    "serve-favicon": "^2.2.0"
  }
}

Some of these are not strictly necessary. For example, I could happily dispense with the favicon. However, I wanted for the setup to be as complete as possible. Note that I’ve added a script as well – to start the server I now use npm start instead of node index.js. It also starts a different file – server.js.

In order to configure the application, I added a configuration JSON file called config.json. Note that the GitHub Repository has the file config-default.json – that’s because YOU MUST EDIT THIS FILE BEFORE USE. Here is the config-default.json file:

{
  "loginRoute": "/account/login",
  "server": {
    "uri": "http://localhost:3000",
    "port": 3000
  },
  "passport": {
    "auth0": {
      "domain": "{{DOMAIN}}.auth0.com",
      "clientid": "{{CLIENTID}}",
      "clientsecret": "{{CLIENTSECRET}}",
      "connections": [ "facebook", "windowslive", "google-oauth2", "twitter" ]
    }
  }
}

If you remember from the social authentication article, I’m using Auth0 as my social authenticator. That system requires a domain, client ID and client secret from the Auth0 website to function. Replace the appropriate pieces in this file and save it as config.json

To make sure that I don’t check in MY config.json, I’ve added it to the .gitignore file.

Talking of auth0, my auth0-strategy.js file is slightly different as well:

/*eslint-env node */

"use strict";

var passport = require("passport"),
    Auth0Strategy = require("passport-auth0"),
    config = require("./config.json");

var strategy = new Auth0Strategy({
  domain: config.passport.auth0.domain,
  clientID: config.passport.auth0.clientid,
  clientSecret: config.passport.auth0.clientsecret,
  callbackURL: "/account/external-callback"
}, function(accessToken, refreshToken, extraParams, profile, done) {
  return done(null, profile);
});

passport.use(strategy);

// This is not a best practice, but we want to keep things simple for now
passport.serializeUser(function(user, done) {
  done(null, user);
});

passport.deserializeUser(function(user, done) {
  done(null, user);
});

module.exports = strategy;

It reads the config.json file and inserts the information you stored there into the constructor for the Auth0Strategy. Note that I’ve also set up ESLint properly – I’m in a node environment (the first line). If you run eslint auth0-strategy.js, this will pass.

I also changed my callback URL. This is to allow a controller to handle the account activities. More on that later, but you will have to insert the new callback URL into the Auth0 Management console for your app.

The final piece of application code (before we get onto the controllers and views) is the server.js file:

/*eslint-env node */

"use strict";

var express = require("express"),
    http = require("http"),
    path = require("path"),
    fs = require("fs"),
    partials = require("express-partials"),
    ejs = require("ejs"),
    passport = require("passport"),
    cookieParser = require("cookie-parser"),
    session = require("express-session"),
    bodyParser = require("body-parser"),
    methodOverride = require("method-override"),
    favicon = require("serve-favicon");

/**
 * Configure the Express server to serve up the application
 * @param {express} app - the express application object
 * @return - the express application object (pipelining allowed)
 */
function configure(app) {
  // Load the server configuration file
  console.info("Loading Server Configuration");
  var config = require("./config.json");

  // Load the authentication strategy
  console.info("Loading Authentication Strategy");
  var authStrategy = require("./auth0-strategy"); // eslint-disable-line no-unused-vars

  // Set up the port that the server will listen on
  console.info("Setting Listening port");
  app.set("port", process.env.PORT || config.server.port || 3000);

  // Set up the location of the views
  console.info("Setting view location");
  app.set("views", path.join(__dirname, "views"));

  // Set Express to use the EJS view engine
  console.info("Configuring view engine");
  app.engine("html", ejs.renderFile);
  app.set("view engine", "html");

  // Set up express to use layouts with the default layout being in
  // /views/Shared/layout.html
  console.info("Configuring layout engine");
  app.set("view options", { defaultLayout: "Shared/layout" });
  app.use(partials());

  // Set up express to use the passport authentication middleware
  console.info("Configuring Passport authentication");
  app.use(cookieParser());
  app.use(session({
    secret: "app-secret",
    resave: false,
    saveUninitialized: false,
    unset: "destroy"
  }));
  app.use(passport.initialize());
  app.use(passport.session());

  // Set up static file serving
  console.info("Configuring static file serving");
  app.use("/client", express.static(path.join(__dirname, "client")));

  // Provide middleware for decoding JSON, URL-encoded body parts
  console.info("Loading Body Parser Middleware");
  app.use(bodyParser.urlencoded({ extended: false }));
  app.use(bodyParser.json());

  // Allows a controller to override HTTP verbs such as PUT or DELETE
  console.info("Loading Method Overrides");
  app.use(methodOverride());

  // Serve up a default favicon
  console.info("Configuring favicon");
  app.use(favicon(path.join(__dirname, "client/favicon.ico")));

  // Dynamically include controllers in the controllers directory
  console.info("Loading Controllers");
  fs.readdirSync("./controllers").forEach(function (file) {
    if (file.substr(-3) === ".js") {
      console.info("Loading Controller " + file);
      var base = "/" + path.basename(file, ".js");
      var route = require("./controllers/" + file);
      app.use(base, route);
    }
  });

  console.info("Configuring Home Controller");
  app.get("/", function(req, res) {
    res.redirect("/home");
  });

  // Return the app so we can pipeline
  console.info("Finished configuring server");
  return app;
}

/*
 * Configure the application
 */
var server = configure(express());
http.createServer(server).listen(server.get("port"), function () {
  console.info("Express Server listening on port " + server.get("port"));
});

Phew – that’s a lot of code. Fortunately, this is all fairly explanatory with the comments that are in there. The only complicated bit is this piece of code that loads the controllers (highlighted at lines 80-89) The first block loads each javascript file in the controllers directory. For each controller, I compute a base URL. If the controller is called home.js, then the base will be /home. I’m expecting the controller to export an Express Router object – more on that when I get to controllers.

Once I’ve configured all the controllers, I set the default home page to redirect to the root document in the home controller. This is just like ASP.NET when you provide a route configuration that includes {controller=Home}.

The Basic Controller Pattern

Let’s take a look at the home controller (controllers/home.js) so that we can understand the logic that goes into it. The home controller has a home page that renders a view. However, the view only gets rendered if the user is authenticated. If the user is not authenticated, the user is redirected to the account controller:

/*eslint-env node */

"use strict";

var express = require("express"),
    path = require("path"),
    config = require("../config.json"),
    extend = require("extend");

var router = express.Router(), // eslint-disable-line new-cap
    controller = path.basename(__filename, ".js"),
    loginRoute = config.loginRoute || "/account/login";

/**
 * Set of default properties for the rendering engine
 */
function defaultProperties(req) {
  return {
    title: "Unknown",   // Default title in case the developer doesn't set one
    user: req.user
  };
}

/**
 * GET /{controller=Home}/index
 */
function index(req, res) {
  if (!req.isAuthenticated()) {
    res.redirect(loginRoute);
    return;
  }
  res.render(controller + "/index.html", extend({}, defaultProperties(req), {
    title: "Home"
  }));
}

// Per-route functionality
router.get("/index", index);

// Default route is to GET index
router.get("/", index);

module.exports = router;

First off, I create an Express router. I also compute the controller name based on the filename of the javascript file. Finally, I compute the loginRoute – if it is specified in the configuration, then use that, otherwise I have a default location specified.

The defaultProperties() method returns an object with some information that the layout needs. The req object is not available in the layout and I want to display my name and maybe other information from the authentication object. In addition, I want to ensure that things don’t break just because I didn’t give all the parameters the layout needs for rendering.

The index() method is the handler for the /index route. The initial part just handles redirection if the user is not authenticated. The render() statement renders a view based on the controller – In this case, this is the home controller, so it will look in views/home/index.html for its view.

The extend() statement is an interesting one and is provided by a library. It combines multiple objects together, with an order of precedence. I start with the empty object, add in the default properties, then add in the route specific properties. I suppose I could do something like:

/**
 * Render an appropriate view
 */
function view(req, res, viewName, locals) {
  res.render(controller + "/" + viewName + ".html",
    extend({}, defaultProperties(req), locals));
}

As an appropriate helper. Then the index function becomes:

/**
 * GET /{controller=Home}/index
 */
function index(req, res) {
  if (!req.isAuthenticated()) {
    res.redirect(loginRoute);
    return;
  }
  view(req, res, "index", { title: "Home" });
}

This is maybe slightly more readable, but not necessary.

The final piece of the module wires up the routes relative to the controller – I’ve given two routes, one for / and one for /index – both identical. Thus, when the user browses to /home or /home/index, they get the same page. Finally, I export the router I created. This is the object that the configuration code in server.js gets – it then links it into the main express router using the controller name as the location.

The Basic View Pattern

To go along with the basic controller, I need a basic view. All the views are relative to ./views/{controller} in this pattern. My ./views/home/index.html file is basic indeed:

<h1>Index</h1>

I want that wrapped in a layout. I included the following code in server.js to specify the default location of the layout (assuming one was not specified):

  console.info("Configuring layout engine");
  app.set("view options", { defaultLayout: "Shared/layout" });
  app.use(partials());

This tells me the layout, by default, is in ./views/Shared/layout.html:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <meta name="description" content="A basic web application">
  <meta name="author" content="">

  <title><%= title %> | Basic WebApp</title>

  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css">
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css">
  <!--[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]-->

  <link rel="stylesheet" href="/client/layout.css">

</head>
<body>
  <div id="wrapper">
    <nav class="navbar navbar-inverse navbar-fixed-top" role="navigation">
      <div class="navbar-header">
        <a class="navbar-brand" href="/">Basic WebApp</a>
      </div>
      <!-- Top Menu Items -->
      <ul class="nav navbar-right top-nav">
        <li><a href="/account/profile"><%= user.displayName %></a></li>
        <li><a href="/account/logout">
          <i class="fa fa-sign-out"></i>
          <span class="sr-only">Sign Out</span>
        </a></li>
      </ul>
    </nav>
    <section id="page-wrapper">
      <div class="container-fluid">
        <%- body %>
      </div> <!-- /.container-fluid -->
    </section> <!-- /#page-wrapper -->
  </div> <!-- /#wrapper -->

  <script src="http://code.jquery.com/jquery-2.1.3.min.js"></script>
  <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js"></script>
</body>
</html>

I’ve included a default navbar that includes the user display name and a link to the logout. I have not created an /account/profile in this article (and there isn’t going to be one – that’s for you to write). Note that I’ve also added in some CSS (which I’m not going to show off in the article – go check out the GitHub Repository).

This is very similar to the Razor _Shared.cshtml file in ASP.NET. The rendering is a little different due to the change in rendering engine, but it should feel familiar.

The Account Controller

In ASP.NET, the Account Controller was special. It’s no different here. I’m only doing Social Authentication in this version. In the Auth0 management portal, I’ve turned on Twitter, Facebook, Windows Live and Google authentication. I have not changed the API keys from the Auth0 development keys. If you were deploying this in production (and paying Auth0), then you would definitely want to register your own keys with Auth0.

If you click on your app and then on Connections (along the top), you should see something like this:

blog-code-0521-1

Now that is done, let’s take a look at the controller controllers/account.js:

/*eslint-env node */

"use strict";

var express = require("express"),
    passport = require("passport"),
    path = require("path"),
    config = require("../config.json");

var router = express.Router(), // eslint-disable-line new-cap
    controller = path.basename(__filename, ".js");

/**
 * Build a URL for a specific provider based on the configuration and
 * the provider name
 */
function buildurl(provider) {
  var server = config.server.uri || "http://localhost:3000";

  var url = "https://" + config.passport.auth0.domain + "/authorize" +
    "?response_type=code&scope=openid%20profile" +
    "&client_id=" + config.passport.auth0.clientid +
    "&redirect_uri=" + server + "/" + controller + "/external-callback" +
    "&connection=" + provider;

  return url;
}

Up to this point, it’s a regular controller. I’ve defined a private function for building a URL to link into the Auth0 system. I’m going to pass these URLs as locals in the login method – speaking of which:

/**
 * GET /{controller}/login
 */
function login(req, res) {
  var locals = {
    layout: false,
    connections: {}
  };
  var connections = config.passport.auth0.connections || [];
  for (var i = 0; i < connections.length; i++) {
    locals.connections[connections[i].replace("-","_")] = buildurl(connections[i]);
  }

  res.render(controller + "/login.html", locals);
}

/**
 * GET /{controller}/logout
 */
function logout(req, res) {
  req.logout();
  res.redirect("/");
}

// Wire up Per-route functionality
router.get("/login", login);
router.get("/logout", logout);

This section is all about wiring up the login and logout routes. The login route will display the ./views/account/login.html view, and I am passing in the list of connections from the config.json file. You can have as many as you want here.

// Social Identity callback - set this in the Auth0 Manage App page
router.get(
  "/external-callback",
  passport.authenticate("auth0", {
    failureRedirect: "/" + controller + "/failure-callback"
  }),
  function (req, res) {
    if (!req.user) {
      throw new Error("user is null");
    }
    res.redirect("/");
  }
);

module.exports = router;

Finally, we need to handle the callback. This is set in the auth0-strategy file and this file – in two places. Firstly, in the buildurl() method and then again in the route to handle the external callback. You can specify a new route /failure-callback that displays a “Oh Noes – Something bad happened” view, or you can just let it 404. If everything is successful, we redirect back to the home page – this time authenticated.

The ./views/account/login.html is a complete HTML page. I’ve specified “layout: false” in the locals – a signal to the rendering engine to not use a layout file:

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">

  <!-- Bootstrap, Bootstrap-Social, Font-Awesome -->
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css">
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css">

  <!-- My minimal stylesheet -->
  <link rel="stylesheet" href="/client/bootstrap-social.css">
  <link rel="stylesheet" href="/client/login.css">
  <title>Login | Basic WebApp</title>
</head>
<body>
  <div id="outer">
    <h2>Login with your Social Provider</h2>
    <div class="row">
      <div class="col-xs-12 col-sm-6 col-md-6 col-lg-6 social-buttons">
        <a class="btn btn-block btn-social btn-twitter" href="<%= connections.twitter %>">
          <i class="fa fa-twitter"></i> Sign in with Twitter
        </a>
      </div>
      <div class="col-xs-12 col-sm-6 col-md-6 col-lg-6 social-buttons">
        <a class="btn btn-block btn-social btn-facebook" href="<%= connections.facebook %>">
          <i class="fa fa-facebook"></i> Sign in with Facebook
        </a>
      </div>
      <div class="col-xs-12 col-sm-6 col-md-6 col-lg-6 social-buttons">
        <a class="btn btn-block btn-social btn-microsoft" href="<%= connections.windowslive %>">
          <i class="fa fa-windows"></i> Sign in with Microsoft
        </a>
      </div>
      <div class="col-xs-12 col-sm-6 col-md-6 col-lg-6 social-buttons">
        <a class="btn btn-block btn-social btn-google" href="<%= connections.google_oauth2 %>">
          <i class="fa fa-google"></i> Sign in with Google
        </a>
      </div>
    </div>
  </div>
</body>
</html>

I’ve downloaded bootstrap-social.css and put it in my client static area for this.

With all this code, I now have a complete basic web app that authenticates via one of four social logins and produces a nice Bootstrap-enabled front page.

You can get all the code from my GitHub Repository.

Social Authentication – Node Style

I’m currently in the middle of a Node investigation. Here was the list of my requirements:

  1. I need to be able to run a small web server
  2. I need to be able to handle templated views with server-side code
  3. I need to be able to do social authentication
  4. I need to be able to use an MVC architecture
  5. I need to be able to provide a Web API
  6. I need to be able to publish a node app to Azure
  7. I need to be able to edit node applications in Visual Studio 2015

Today is all about social authentication. Research on google tells me that I should use Passport which is a modular middleware for – you guessed it – authentication in a node/express environment. I recently met with the guys at Auth0 and their technology impressed me. You can do one call to one provider and authenticate to many environments – including enterprise accounts like Active Directory and Azure AD. I just want Twitter right now, but that is simply awesome, so I’m planning on integrating that technology as well.

Step 1: Sign up for a free Auth0 Account

You only start paying for Auth0 usage when you go into production. I’m not going into production, so I am using their free account. Just go onto their home page and click the big button to sign up.

Their process also walks you through creating a default app. This is perfectly fine for what I’m going to do – just make sure you select Twitter authentication when you do this process.

Step 2: Set up the Auth0 Default App

In the Auth0 management screen, select the Apps / APIs option on the left hand menu, then click on the Default App. A screen shot is shown below with obfuscated client credentials.

blog-code-0519-1

Note the callback URL. I have to set that to whatever my website is running as. The URL http://localhost:3000 is where my node application lives. If I were running this in Azure, then I would have something like http://shellmonger-basic-app.azurewebsites.net/. Take note of the domain, client ID and client secret that I have blacked out – these are important later.

Step 3: Write an Auth0 strategy file

While we are logged on to the auth0 management portal, click over to Quick Start and select a Regular Web Site on Node.JS. It has some boiler-plate code there. In Step 2, there is a section of code for configuring Passport for Auth0. Cut and paste that into a file in your project called auth0-strategy.js. Mine (with adjustments for obfuscating secrets) looks like this:

var passport = require('passport');
var Auth0Strategy = require('passport-auth0');

var strategy = new Auth0Strategy({
    domain:       '{{DOMAIN}}.auth0.com',
    clientID:     '{{CLIENTID}}',
    clientSecret: '{{CLIENTSECRET}}',
    callbackURL:  '/callback'
  }, function(accessToken, refreshToken, extraParams, profile, done) {
    // accessToken is the token to call Auth0 API (not needed in the most cases)
    // extraParams.id_token has the JSON Web Token
    // profile has all the information from the user
    return done(null, profile);
  });

passport.use(strategy);

// This is not a best practice, but we want to keep things simple for now
passport.serializeUser(function(user, done) {
  done(null, user);
});

passport.deserializeUser(function(user, done) {
  done(null, user);
});

module.exports = strategy;

The three pieces I have obfuscated are the three pieces I blacked out when configuring the default app above.

Step 4: Add a Login Page

I cheated for the login page. I have a client/login.html file with the following contents:

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>Login</title>
</head>
<body>
  <h1><a href="https://{{DOMAIN}}.auth0.com/authorize?response_type=code&scope=openid%20profile&client_id={{CLIENTID}}&redirect_uri=http://localhost:3000/callback&connection=twitter">Twitter</a></h1>
</html>

The URL is further down the quick start page. In the drop-down for section 6, select “Plain Link” and you will get this URL. Now I just have to click on that link and it will initiate the login sequence.

Step 5: Update the main server file

Finally, I need to update the main server file – index.js – to add in authentication. First of all, I need some new libraries. Install them with npm:

npm install --save passport passport-auth0 cookie-parser express-session

I also need to bring in the libraries at the top of index.js:

var express = require("express"),
    partials = require("express-partials"),
    ejs = require("ejs"),
    passport = require("passport"),
    cookieParser = require("cookie-parser"),
    session = require("express-session"),
    auth0strategy = require("./auth0-strategy");

There are three things I need to do in the main server file:

  1. Configure the Passport system with the Auth0 Strategy
  2. Do a redirect to the login page if the user is unauthenticated
  3. Handle the callback from Auth0

First up is configuration. I’ve added the following code (which is boilerplate from the auth0 quick start):

// Set up express to use the passport authentication middleware
app.use(cookieParser());
app.use(session({ secret: "my-little-secret" }));
app.use(passport.initialize());
app.use(passport.session());

This is placed alongside the other app.use() method calls.

Let’s say a user is unauthenticated. They browse to the home page. The first thing I want to happen is to redirect the user to the login page that I created in Step 4. To do that, I’ve added some code to the home page view handler. In fact, this was why I wanted a view handler in the first place – so I could inject some server side code:

// Serve up pages - Home Page
app.get("/", function(req, res) {
  if (!req.isAuthenticated()) {
    res.redirect("/client/login.html");
  } else {
    res.render("index", {
      title: "Index Page (from index.js)",
      user: req.user
    });
  }
});

The user will get served up the /client/login.html page which has that single Twitter link on it. They will click on that and be redirected to the Auth0 site. Auth0 will do it’s magic to authenticate the user and redirect back to the redirect_url from the Twitter link in /client/login.html (this redirect URL is also registered on the Auth0 site).

That redirection goes to /callback. I’ve added the following code directly before the home page handler to handle the callback:

// Serve up pages - Callback handler from Auth0
app.get("/callback",
  passport.authenticate("auth0", {
    failureRedirect: "/client/failure.html"
  }),
  function(req, res) {
    if (!req.user) {
      throw new Error("user is null");
    }
    console.log("User is %o", req.user);
    res.redirect("/");
  }
);

When the user is redirected back to /callback, it presents a new cookie. The passport.authenticate method calls does a call back to Auth0 to ask if the cookie is valid and if so to fill in the details of the user. If that succeeds, then the user is redirected back to the home page, but this time in an authenticated state.

Note I’ve printed the req.user object. This has all sorts of interesting information in it:

User is %o { provider: 'twitter',
  displayName: 'Adrian Hall',
  id: 'twitter|257173506',
  name: { familyName: undefined, givenName: undefined },
  picture: 'https://pbs.twimg.com/profile_images/1668098857/May_2011_Photo_normal.png',
  nickname: 'Adrian Hall',
  identities:
   [ { access_token: '**REMOVED**',
       access_token_secret: '**REMOVED**',
       provider: 'twitter',
       user_id: 257173506,
       connection: 'twitter',
       isSocial: true } ],
  _json:
   { name: 'Adrian Hall',
     picture: 'https://pbs.twimg.com/profile_images/1668098857/May_2011_Photo_normal.png',
     description: 'Big Data in IT operations.',
     lang: 'en',
     location: 'Seattle, WA, US',
     screen_name: 'FizzyInTheHall',
     time_zone: 'Pacific Time (US &amp; Canada)',
     url: 'http://t.co/7dxPr1cxdj',
     utc_offset: -25200,
     clientID: '{{CLIENTID}}',
     user_id: 'twitter|257173506',
     nickname: 'Adrian Hall',
     identities: [ [Object] ],
     created_at: '2015-04-27T17:19:41.812Z' },
  _raw: '**REMOVED**' }

I could add something like <%= user.displayName %> to my view (since I’ve added the user object to the model) and get the display name.

Final Thoughts on Authentication

There are some competing styles for authentication – OAuth 1, OAuth 2 and OpenID are some of the more visible and commonly used ones in social authentication. Which one is better? That requires an understanding of the politics and technical development that are beyond me – which is why I think a provider like Auth0 (or its arch nemesis – oauth.io) is a good idea. In the end, writing one connector and handling multiple providers makes life easier for you – the developer – with no loss of functionality for your user.

It’s a good idea to get a good grasp on how these work so you can see what is going on via Fiddler when authentication is not working.

As always, my work is published on my GitHub Repository.