developers

Planet-scale authentication with Auth0 and Azure DocumentDB

Learn how to integrate Azure DocumentDB as your Auth0's custom user database and take advantage of this blazing fast cloud NoSQL database service.

Oct 11, 20166 min read


TL;DR: In this article you will learn how to integrate Auth0 with the fast and scalable Azure DocumentDB as a custom database connection and use it in your Auth0 applications.


Auth0 offers a highly performant and secure user store to maintain your users’ profiles. It is also a common solution if you want to store your users’ login information in your own database where you keep all of your application's data; in this case, Auth0 provides you with several identity providers you can use to integrate. One such database is Azure DocumentDB, a blazing-fast NoSQL service for highly available and globally distributed applications.

During this article, we will guide you into integrating Auth0 and Azure DocumentDB so your users' profiles are stored on your cloud NoSQL database.

Authentication integrated

Let’s start by noting the diversity of custom database identity providers that Auth0 supports.

This list includes MySQL, Sql Server (both on-premises and on Azure), PostgreSQL, ASP.NET Membership Providers, any Basic Auth web service and MongoDB. We will focus on this last one since Azure DocumentDB now supports the MongoDB protocol.

Auth0 custom providers list

You can see the full Custom Database Identity providers' documentation in the official docs.

The integration is achieved by customizable Node.js scripts that can be coded directly on Auth0’s configuration dashboard manually or using a wide array of templates.

To sum up, we will be using the MongoDB protocol supported by Auth0 identity provider to connect to our Azure DocumentDB and store/retrieve our users' information by custom Node.js scripts.

Creating our database

As we mentioned before, Azure DocumentDB supports the creation of databases that support the MongoDB protocol (as of the writing of this article, this feature is in preview). We must access the Azure Portal and filter for DocumentDB services to find the version with MongoDB support:

Searching the Azure Portal Creating our Azure DocumentDB service

Once created, we will be able to access our connection string credentials on the instance blade. We need to take note of these values because we will use them later on the integration:

Obtaining connection string

After creating our service, we will proceed to create a Database and a Collection to store our data. If you are not familiar with the Database and Collection concepts for NoSQL databases, a Database can hold multiple Collections and each Collection will store Documents (in JSON format). You will be billed for each Collection, so plan your distribution accordingly.

You can review the complete concept diagram in the official documentation.

We will create an "auth0" database:

Creating a database

And a "users" collection:

Creating a collection

Azure DocumentDB lets you define a dynamic and scalable throughput you can increase later as your application demands.

Establishing the integration

In this step, we will use the connection string information we collected in the Azure Portal to create a custom database provider. In your Auth0 Dashboard, you will see a Connections > Database configuration section:

Auth0's Dashboard Connections menu

Once there, you can Create a Db Connection:

Create Db Connection

You will be asked for a name:

Setting up Connection name

Once created, we will go to the Custom Database tab and enable the "Use my own database" toggle, which will activate the lower Database Action Scripts section.

The Auth0 editor allows us to define global variables to reuse on all our Node.js scripts. Let's start by setting a global connection string; on the Settings subsection, we create a "ConnectionString" key and paste the Connection String value we obtained from the Azure Portal with the added database name.

Your copied string looks like this:

mongodb://<your_service_name>:<your_password>==@<your_service_name>.documents.azure.com:10250/?ssl=true

We will add the database name after the port, like this:

mongodb://<your_service_name>:<your_password>==@<your_service_name>.documents.azure.com:10250/auth0?ssl=true

Setting up global variable

In our Node.js scripts, we can access this value by the global variable

configuration.ConnectionString
.

Now, we will define our custom Login, Create, Verify, Change Password and Delete scripts using our predefined variable:

Login

function login (email, password, callback) {
  mongo(configuration.ConnectionString, function (db) {
    var users = db.collection('users');
    users.findOne({email: email}, function (err, user) {


if (err) return callback(err);

      if (!user) return callback();

      if (!bcrypt.compareSync(password, user.password)) {
        return callback();
      }
      callback(null,   {
        user_id:      user._id.toString(),
        nickname:     user.nickname,
        email:        user.email
      });

    });  
  });
}

Create

function create (user, callback) {
  mongo(configuration.ConnectionString, function (db) {
    var users = db.collection('users');

    users.findOne({ email: user.email }, function (err, withSameMail) {

      if (err) return callback(err);
      if (withSameMail) return callback(new Error('the user already exists'));

      user.password = bcrypt.hashSync(user.password, 10);

      users.insert(user, function (err, inserted) {  
        if (err) return callback(err);
        callback(null);
      });
    });
  });
}

Verify

function verify (email, callback) {
  mongo(configuration.ConnectionString, function (db) {
    var users = db.collection('users');
    var query = { email: email, email_verified: false };

    users.update(query, { $set: { email_verified: true } }, function (err, count) {
      if (err) return callback(err);
      callback(null, count > 0);
    });
  });
}

Change Password

function changePassword (email, newPassword, callback) {
  mongo(configuration.ConnectionString, function (db) {
    var users = db.collection('users');

    var hashedPassword = bcrypt.hashSync(newPassword, 10);

    users.update({ email: email }, { $set: { password: hashedPassword } }, function (err, count) {
      if (err) return callback(err);
      callback(null, count > 0);
    });
  });
}

Delete

function remove (id, callback) {
  mongo(configuration.ConnectionString, function (db) {
    var users = db.collection('users');
      var o_id = new mongo.ObjectID(id);
      users.remove({ _id: o_id }, function (err) {
      if (err) return callback(err);
      callback(null);
    });
  });
}

And we can test the connection by running the Create script from within the interface:

Testing the connection

If we query the content of the Azure DocumentDB collection through the Azure Portal, we will find our created user:

{
    "_id": {
      "$oid": "57f2983189b7550100e909e4"
    },
    "tenant": "ealsur",
    "connection": "DocumentDB",
    "email": "ealsur@ealsur.com.ar",
    "password": "$2a$10$hiSfzkpLjQUXivV4AvdakOCsTqDAYeSAx1Dn2HfPW6XuU28i5wgpq",
    "debug": true,
    "id": "57f2983189b7550100e909e4",
    "_rid": "u11qAL9JdQATAAAAAAAAAA==",
    "_self": "dbs/u11qAA==/colls/u11qAL9JdQA=/docs/u11qAL9JdQATAAAAAAAAAA==/",
    "_etag": "\"08007436-0000-0000-0000-57f298320000\"",
    "_attachments": "attachments/",
    "_ts": 1475516462
}

As you can see, this is a plain JSON object that is readable through any application-consuming collection.

Finally, we can create a new Client Application and define that we will use our custom Azure DocumentDB database on the Connections configuration.

For a detailed concept explanation, you can read the official Applications documentation.

Defining the Application connection

This will let our Client Application access and use the DocumentDB identity provider.

User profile customization

Since Azure DocumentDB uses JSON to store our user profiles, we can take advantage of this dynamic data format and customize our users' profile data during sign-up.

To achieve this, we can use Auth0's Lock and configure the required additional signup fields. This will generate the new fields and store them on our collection as part of the user profile without any extra work.

You can also view the complete Custom Signup documentation for a more detailed explanation.

Conclusion

Auth0’s custom database flexibility lets us use one of the most dynamic and fast NoSQL service offerings available. Azure DocumentDB has the ability to scale and grow as your business or application does in a seemingly easy way.