How do you want to login today

Spot Invoice is our simple invoicing tool: visual invoice design lets you see exactly what you'll end up with, and PDF printing gets you a perfect invoice every time. Try Spot Invoice now

When building Spot Invoice we were faced with the eternal authentication question: do you start off with just Facebook or Twitter authentication or do you start off with a username/email address and password? We've seen many products that pick social authentication for the implementation speed, ease of use and security features (as well as the other potential benefits like sharing and access to user relationships).

The social authentication options (Facebook, Twitter, Google+, etc) make some things easier: for the users who don't want to create yet-another-username-and-password (that they'll forget), they can just log right in. However, a quick search through Google produces such gems as this and this.

Opinions tend to be strong about the authentication question: and very often you'll find that people will make loud comments (and drive discussion about your product) based on the choice of authentication option. For Spot Invoice, we wanted to make sure no one felt turned away by our choice of authentication: we knew this meant we'd need to support both direct login as well as social authentication. The only question really was how.

We looked over the social authentication options, and after some thought settled on the following set:

  • Email address/password: for the users who want to create a password
  • Facebook
  • Google
  • Github
  • Microsoft account (this is oddly named: first it was live.com, then it was liveconnect, then it was outlook...)

We ruled out Twitter: we wanted to have a valid email address for every user, and Twitter doesn't provide a sanctioned way to ask the user for the email address associated with an account (well, we spent 15 minutes looking and couldn't find one).

The really neat thing about all the social options above (Microsoft included) was that they all offer fairly straightforward authentication implementations: OAuth 2 for everyone except Facebook, and Facebook is..well..Facebook, so we went with their implementation (and we believe they have OAuth 2 support as well, but we already had Facebook auth code from a previous project, so it didn't take much more work).

There are a number of excellent authentication libraries for the NodeJS platform: we looked at Passport and EveryAuth. One thing none of them cover, however, is the actual persistent user model: the application's representation of what a user is and how said user is authenticated.

Most simple user authentication structures look something like this (taken from https://www.junnark.com/blog/detail/build-a-web-chat-application-part-2-chat-with-other-users-privately-in-c-sharp-3-5):

with the core user representation stored with the password (hopefully suitably hashed!). But that wouldn't work for us: we need to separate the account from the authentication. This would look something like this:

We track how the user authenticates in a separate table: we store the specific provider in a field (provider), and the unique identity that the provider asserts in a separate field (refid), then we point to the actual user. For users who opt for our email address and password we have an internal provider; for all the third-party auth systems, we can set the provider field to a magic string that tells us how this user authenticates. The system can separate out the different authentication strategies, but crucially they all co-exist quite nicely.

It took a little extra work, but once it was in place it works really well: adding new authentication providers can be quickly done by providing an appropriate OAuth 2 endpoint. In the future we can even provide a user the option of switching their authentication: if a user ever decides to give up (for example!) Google completely, they could keep their account but start authenticating with Github.

And, as originally intended: it avoids most flamewars about our supported authentication, since we have something for everyone!