Often my clients need simple, inexpensive, yet scalable solution for user management. This is especially true of clients that are startups, or are developing MVPs. Cost and scalability are important.

Facebook’s Parse.com server was my go-to tool until Facebook kicked it to the curb. It has since been open sourced, but still remains somewhat of a black box. (Unless you want to learn a new framework.) Now that Microsoft has added Azure Functions to its lineup, there is something simplier to set up.

With Azure, it is easy to implement a simple authentication system that uses best practices for passwords and hashing, and the creation of JWTs.   Azure Functions are Microsoft’s answer to AWS Lambda. Like AWS lambda, Azure Functions are serverless pieces of functionality triggered by a customizable variety of things. You are charged by the amount of memory in GB/sec for the time consumed by each individual action.

“HTTP triggers” are a REST endpoint that executes a specific Azure Function. There are other kinds of triggers such as queue events and timers. This post will focus on HTTP triggers.

Azure Functions are built on top of Azure Web API, but each function is in a separate directory. Azure function supports multiple languages, such as C#, python, PHP, JavaScript and others. I opted to use C #, as that is my language of choice.

An Azure Function

There are a couple configuration files in each directory which let Azure Functions know several things related to each function. In the case of HTTP triggers, this includes the REST route and security on the function.

Files in an Azure Function directory.

function.json

Though Azure Functions supports debugging, they don’t yet support unit testing. To make it easier to test this project, I put the bulk of the functionality into a shared assembly. The Azure function calls into the shared assembly which parses parameters, delegates to sub-components and formats the output. This allows me to quickly develop and debug the basic functionality. Additionally, it should be compatible with Azure Web Api projects, though I haven’t tested it yet.

Simple Authentication

This simple authentication has 3 HTTP methods: Register, Login and GetCurrentUser. The first two methods are straightforward. GetCurrentUser is there to show how to validate the java script web token (JWT).

For data storage I decided to use Microsoft’s NOSQL solution DocumentDB. DocumentDB’ s pricing model is based on reserved units of processing and max storage size. (Check https://azure.microsoft.com/en-us/pricing/details/documentdb/ for more pricing details.)

This project uses a simple abstraction for database access to facilitate mocking for unit tests, and to allow a way to use another database. The functions are very thin wrappers around calls into the shared assembly which coerce values, validate input, catch errors and return results accordingly.

There are three layers. Layer one coerces parameters from HttpRequestMessage objects and formats the HttpResponseMessage. It calls into an object that does the bulk of the work but has no awareness of http request or response messages. Finally, there is a database abstraction layer, which is concerned with finding User objects based on ID, email address or email validation code, and saving the user objects.

Creating a User

I followed best practices by using hashed passwords and user specific salt values. Additionally, I decided to use JSON Web tokens that can be passed into API calls for when the user is authenticated.

User registration simply becomes a matter of making sure the normalized email address is unused/unique, initializing the salt value, and then hashing the password storing it. I used code from here (reference) to store the hashed password. The hashed password and the salt are stripped from the user data when returned from a function. At this point I do not issue a token, because in the future I will require email validation.

Authenticating a User

User authentication takes an email address and a password. The user record that corresponds to the email address is retrieved, and the attempted password is hashed using the salt from the record. If the hash value and the hashed password in the user record match, then I return an HTTP 200, a sanitized user record, and the JWT. The JWT is non-standard right now and simply contains a creation date and expiration date, and the ID of the authenticated user.

If the two hashed values do not match, and HTTP code of 401 (unauthorized). It is considered best practice to give no indication if it is the email or the pastor that is incorrect so that they would be hacker cannot test for valid emails.

Verifying the User Authentication

If there are other Azure Functions that require the authenticated users, the JWT needs to be passed in. To check it, it needs to be unwrapped, the signature tested, and the expiration time checked against the current time. If the signature is incorrect, or the expiration time is passed then an HTTP 401 would be returned.

Of note: JWT is what is as known a bearer token. This means that no matter where this token comes from it is considered good. Some people add the hashed IP address that was used to authenticate to the token, and that is compared at the time the particular call is made. If the hashed IP address don’t match, then it is assumed that the token is invalid:

A couple notes about the code.

First, I use the JWT library from here https://github.com/jwt-dotnet/jwt However, the nuget package is compiled for .Net 4.6, but Azure Functions only work with .Net 4.5 as of this writing. For ease, I just copied the source in verbatim.

Second, I created some extension methods around the User object to create objects, set passwords and test password matches. Likewise, there is a helper class for JWTs called Tokens.

Testing

To make it somewhat easier to test I wrote the Azure Functions to work as either a GET or POST. That way I can simply use a browser and type in the correct values in that URL and press enter and observe the results.

Here is the response indented.

Next Steps

There are several things I will add over time:

  • Controlling what gets returned from the GetCurrentUser call.
  • Common UX patterns such as the onboarding process (see User Experience:  Inviting users to your Android or iOS app Part 1 and Part 2)
  • OAuth 2.0 and/or OpenId connect. Since this supports JWTs, it shouldn’t be too hard to add the extra steps that allow for OpenId connect.
  • Let’s encrypt support. There is a Microsoft Web API plugin that can do this. and since Azure Functions use Web APIs, it isn’t too hard to get it hooked up.

References

  1. https://crackstation.net/hashing-security.htm
  2. https://github.com/defuse/password-hashing
  3. https://github.com/jwt-dotnet/jwt
  4. https://github.com/curtisshipley/BlueDog