Offline Sync with Azure Mobile Apps and Apache Cordova

In the past, I’ve introduced you to a TodoList application built in Apache Cordova so that it is available for iOS, Android or any other platform that Apache Cordova supports. Recently, we released a new beta for the Azure Mobile Apps Cordova SDK that supports offline sync, which is a feature we didn’t have.

Underneath, the Cordova offline sync functionality uses SQLite – this means it isn’t an option at this point for HTML/JS applications. We’ll have to work out how to do this with IndexDB or something similar, but for now that isn’t an option without a lot of custom work.

Let’s take a look at the differences.

Step 1: New variables

Just like other clients, I need a local store reference and a sync context that is used to keep track of the operational aspects for synchronization:

    var client,        // Connection to the Azure Mobile App backend
        store,         // Sqlite store to use for offline data sync
        syncContext,   // Offline data sync context
        todoItemTable; // Reference to a table endpoint on backend

Step 2: Initialization

All the initialization is done in the onDeviceReady() method. I have to set up a model so that the SQLite database is set up to match what is on the server:

function onDeviceReady() {

    // Create the connection to the backend
    client = new WindowsAzure.MobileServiceClient('https://yoursite.azurewebsites.net');

    // Set up the SQLite database
    store = new WindowsAzure.MobileServiceSqliteStore();

    // Define the table schema
    store.defineTable({
        name: 'todoitem',
        columnDefinitions: {
            // sync interface
            id: 'string',
            deleted: 'boolean',
            version: 'string',
            // Now for the model
            text: 'string',
            complete: 'boolean
        }
    }).then(function () {
        // Initialize the sync context
        syncContext = client.getSyncContext();
        syncContext.pushHandler = {
            onConflict: function (serverRecord, clientRecord, pushError) {
                window.alert('TODO: onConflict');
            },
            onError: function(pushError) {
                window.alert('TODO: onError');
            }
        };
        return syncContext.initialize(store);
    }).then(function () {
        // I can now get a reference to the table
        todoItemTable = client.getSyncTable(tableName);

        refreshData();

        $('#add-item').submit(addItemHandler);
        $('#refresh').on('click', refreshData);
    });
}

There are three distinct areas here, separated by promises. The first promise defines the tables. If you are using multiple tables, you must ensure that all promises are complete before progressing to the next section. You can do this with Promise.all() as an example.

The second section initializes the sync context. You need to define two sections for the push handler – the conflict handler and the error handler. I’ll go into the details of a conflict handler at a later date, but this is definitely something you will want to spend some time thinking about. Do you want the last one in to be the winner, or the current client edition to be the winner, or do you want to prompt the user on conflicts? It’s all possible.

Once I have created a sync context, I can get a reference to the local SQLite database table, which is used instead of the getTable() call that it replaces. The rest of the code is identical – I refresh the data and add the event handlers.

Step 3: Adjusting the Refresh

In the past, refresh was just a query to the backend. Now I need to do something a bit different. When refresh is clicked, I want to do the push/pull cycle for synchronizing the data.

function refreshData() {
    updateSummaryMessage('Loading data from Azure');
    syncContext.push().then(function () {
        return syncContext.pull(new WindowsAzure.Query('todoitem'));
    }).then(function () {
        todoItemtable
            .where({ complete: false })
            .read()
            .then(createTodoItemList, handleError);
    });
}

Just like the initialization, the SDK uses promises to proceed asynchronously. First push (which resolves as a promise), then pull (which also resolves as a promise) and finally you do EXACTLY THE SAME THING AS BEFORE – you query the table, read the results and then build the todo list. Seriously – this bit really didn’t change.

That means you can add offline to your app without changing your existing code – just add the initialization and something to trigger the push/pull.

Wrap Up

This is still a beta, which means a work-in-progress. Feel free to try it out and give us feedback. You can file issues and ideas at our GitHub repository.

Cross-posted to the Azure App Service Team Blog.

30 Days of Zumo.v2 (Azure Mobile Apps): Day 23 – Understanding Push Notifications

So far, I’ve covered local and remote development, enterprise authentication patterns, table controllers, offline sync and custom APIs. There is one big section of functionality I have not covered yet which is very mobile focused – push notifications. Classically, these are the little pop-up messages you get on your phone to tell you your friend has tagged you in a post, or your favorite news app has some juicy breaking news for you. Push notifications is an out-of-band mechanism that can be used to inform your mobile app that they need to do something. Just like authentication, there are more moving parts. Unfortunately, you don’t own one of them and there is little you can do to control it.

Registering Your Device

There are two distinct processes that you need to understand – registering your device and sending a push. Let’s take a look at registering your device first. There are four distinct steps to registering your device:

day-23-p1

Step 1: Use a platform-specific push notification SDK to retrieve your unique device ID and send it to the platform notification service. The platform notification services are run by the major providers – Apple devices use APNS; Android devices use GCM and Microsoft devices use WNS. There are a handful of others as well. Registering with the platform notification service has absolutely nothing to do with Azure – it’s purely between you, your app and the platform provider.

Step 2: The platform notification service will register your device and send you a registration ID back – this could be a URI or a GUID. it depends on the provider. It’s best to assume this registration ID is an opaque blob that you shouldn’t look at. Device registration IDs are unique to the device – not the user logged into the device.

Step 3: Register the device with Azure Mobile Apps. Once you have configured an Azure App Service with a Notification Hub, a default push registration endpoint becomes available (for reference, it lives at /push/installations on your site). The Client SDK can be used to send the registration ID to that endpoint for processing.

Step 4: Azure Mobile Apps registers your device with Notification Hubs. Since you have configured a Notification Hub properly, Azure Mobile Apps will pass through the call to the Notification Hub for you. This is a security convenience – it means you don’t have to distribute a secret for your notification hub with your app (which would be a bad thing). Once this is done, Azure Mobile Apps will send the Notification Hubs installation ID back to confirm registration.

It sounds more complicated than it actually is – the code is minimal. Before I get there, however, I need to configure my Azure App Service with a Notification Hub.

Why use Notification Hubs?

You might be forgiven for wondering why you need notification hubs at all? After all, you can write a custom API to receive device registrations and store them “somewhere” and then interact with the Platform Notification Services directly, thus cutting out the middleman. To my mind there are three very basic reasons why you need Notification Hubs and will inevitably choose to use Notification Hubs:

  1. Cross-platform. At the end of the day, you don’t care whether your device is on Android, iOS or Windows when you are doing a push – you just want it to work. Aside from the registration process (which is always dictated by the PNS), Notification Hubs can isolate you from the actual logic you need to do individual pushes.

  2. Scale. Sure you can write a custom API to deal with device registrations and handle that complexity for yourself, and it feels tempting in small sites. However, the storage and upkeep of the registration database quickly becomes a nightmare. I haven’t even considered the batching and queueing mechanics required to push to more than a couple hundred users. Notification Hubs abstracts the scale architecture away from you, allowing you to concentrate on the code for your app.

  3. Tagging. Ok – so I’m not going to get to this one until the next post, but Notification Hubs builds in a great subscription model that allows you to push to a tag – any device subscribing to that tag gets the push to the tag. Don’t think that’s useful? How about push to user (tag) or push to AAD group (tag)? How about push to Interest (tag)? This is extremely useful.

Notification Hubs has a generous free tier to allow for development – you can have up to a million pushes per month, across 10 hubs and to 500 devices. Higher tiers are still cheap but handle up to 10 million devices at once.

Adding a Notification Hub

To add a notification hub, start at the Azure Portal and select your App Service, then:

  • Click on All Settings -> Push (under the MOBILE menu heading)
  • Click on Notification Hub then + Notification Hub:

day-23-p2

  • Enter a (Unique) name for your notificaion hub – I use the same name as my app name.
  • Notification Hubs are collected into namespaces. Click on Or create new to create a new one and enter a suitable name:

day-23-p3

  • Click on the blue OK button at the bottom, then the Create button (also at the bottom).

If you skip over to the Data Connections settings blade, you will notice you have two connections now – one for notifications and one for data. There are also two connection strings listed in the Application Settings blade.

Now that I have a notification hub, I need to configure the connections to the platform notification services. Each PNS has its own method of creating an application connection, and the methodology is rather robotic – just follow the Azure instructions for the appropriate PNS:

Its relatively commonplace to configure more than one provider. If you are just starting out, I’d recommend configuring GCM – it’s the easiest (and cheapest) to get started. For GCM, once you have your Project Number and API Key, you are done. Just cut-and-paste the API Key into the API Key for the GCM settings on the Notification Hub:

day-23-p4

It’s a good idea to produce a Custom API that returns the push settings needed from the client. For example, you can have a custom API that reads the Project Number from an app setting that you define and returns it as part of a settings object. This ensures that your client configuration remains with you – if the project number needs to change, you can do it on the server rather than distributing a new client.

If you are using Google Authentication + GCM, then you can use the same project in the Google Developer Console.

Adding Push Registration to ASP.NET

The Node.js backend has push notifications “for free” – the registration endpoint is always there. You need to add the push registration to the ASP.NET backend. This is a one-time thing. Start by adding the Microsoft.Azure.Mobile.Server.Notifications NuGet Package (and dependencies, which include the Notification Hubs SDK); then adjust the startup code in the App_Start file:

            // Configure the Azure Mobile Apps section
            new MobileAppConfiguration()
                .AddTables(
                    new MobileAppTableConfiguration()
                        .MapTableControllers()
                        .AddEntityFramework())
                .MapApiControllers()
                .AddPushNotifications()
                .ApplyTo(config);

Publish this code before continuing.

Registering for Push – Apache Cordova Style

I don’t know why, but I prefer Apache Cordova development on the Mac. I’d been using the Visual Studio TACO (Tools for Apache Cordova), but a variety of problems with emulators and the Android SDK caused me to switch back to the Mac for this. One important aspect of doing push notifications on Apache Cordova is the binary image you use – either on the phone or on an emulator. Specifically, you must use an emulator that contains the Google APIs. You can do this in the AVD Manager.

To handle the device to PNS communication, I use a 3rd party plugin – phonegap-plugin-push. This is a fairly standard plugin and is used by most Apache Cordova applications that implement push notifications. To add the plugin to your project:

cordova plugin add phonegap-plugin-push --variable SENDER_ID=your-project-id
cordova plugin add cordova-plugin-device

You can also add it via the Plugins > Custom menu when the config.xml file is open within Visual Studio. Add the Git repository https://github.com/phonegap/phonegap-plugin-push. Note that the phonegap-plugin-push requires certain libraries from the Android SDK so ensure you follow the install instructions. There is a small amount of code needed to bring this in, and it’s all in my app initialization routine:

        // Register for push notifications
        if (typeof PushNotification === 'undefined') {
            console.log('Push Notification Service is unavailable');
        } else {
            console.log('Initializing Push');
            pnsHandler = PushNotification.init({
                android: { senderID: '121035973492' },
                ios: { alert: 'true', badge: 'true', sound: 'true' },
                wns: { }
            });
            console.log('pnsHandler = ', pnsHandler);

            console.log('Registering Push Event Handlers');
            pnsHandler.on('registration', handlePushRegistration);
            pnsHandler.on('notification', handlePushNotification);
            pnsHandler.on('error', handleError);
        }

The important thing to do here is replace the Android senderID with the one for your project. Using mine won’t work. This number isn’t the secret – the API key is the secret (and you should never check secrets into source code, of course). If you’ve followed my advice earlier, you will have to call the custom API to get this number. iOS/APNS and WNS depend on the application being registered and properly configured in the respective app stores for their functionality, so Android is the only one you need to specify something for. I’ve got two functions to write still – handlePushRegistration() is called when the PNS returns my registration ID and handlePushNotification() is called when I actually receive a push notification.

Note that the push notification service is only available after the onDeviceReady() event has fired. The initial check ensures the library is loaded.

Let’s check out registration first. I want to pass the registration ID to the client registration process:

    /**
     * Event Handler for Push Registration ID
     * @event
     */
    function handlePushRegistration(data) {
        console.log('device model == ' + device.model);
        var pns = 'gcm'; // the default
        if (device.model === 'ios') pns = 'apns';
        if (device.model === 'windows') pns = 'wns';

        console.log('Registering with Notification Hub');
        client.push.register(pns, data.registrationId);
    }

The client.push routines are pretty much always pass-throughs for the appropriate Notification Hub routines in the Notification Hubs SDK, so if you want to know what they return, reference the Notification Hubs SDK instead.

The various platform notification services all use a similar format for IDs, so I need to tell Notification Hubs who generated the registration ID. I’m doing this in a very basic way right now – most people use GCM. If you are on iOS or Windows specifically, then use the appropriate one.

Finally, let’s take a look at handling the actual notification:

    /**
     * Event Handler for Push Notification
     * @event
     */
    function handlePushNotification(data) {
        console.log('handlePushNotification: data = ' + JSON.stringify(data));
        alert('PUSH NOTIFICATION:\n'+data.message);
    }

Each push notification has a message, which could be encoded. All I do is print out the message. I’ll deal with some of the more esoteric things you can do with this later on.

Monitoring Registrations

You are probably thinking that the Azure Portal has some amazing things to see registrations so I know what is going on. Sadly, no it doesn’t. However, Visual Studio does have some really great tooling here. Just start up Visual Studio, find the Server Explorer, log into Azure and expand to find your notification hub. Double-click on it will get you a window with the current registrations in it:

day-23-p5

You can also see that two tags are automatically added for me. The first is one based on the installation ID – this is an Azure Mobile App generated GUID that is unique to the app/device combination (but several users could be using the same app/device). The other tag is based on the authenticated user ID – it’s the “stable SID” – i.e. something that the IdP generates for me. I can use this to implement “push to user”. There is more to talk about here, but that’s for another time.

Sending a Test Push Notification

The other thing I can do with the Visual Studio tooling (but if you are on a mac, don’t worry – you can do this bit in the Azure Portal as well) is a test send. That’s “the other tab” in the registration monitor. To use it, just select a Message Type of Android default and hit send.

day-23-p6

Almost immediately (but in reality, it could be a few minutes because of PNS delays), you will see the push notification alert on your application.

Wrap Up

We have only scratched the surface here with one app on one device type with one PNS, but we’ve covered a lot of ground. The Azure Tutorials do a good job of putting together specific push scenarios for each platform. Since there are a lot of details to cover, I recommend doing the tutorials for your platform. In the next post, I’m going to talk about tags and how to register for tags in both Node.js and ASP.NET backends. Until then, todays content is available from my GitHub repository.

30 Days of Zumo.v2 (Azure Mobile Apps): Day 5 – Custom Authentication

Over the past two articles, I’ve explored using a server-flow and a client-flow technique to authenticate users to Azure AD and accessing information with Azure Mobile Apps. However, there are times I don’t want social authentication – I want users to sign up to my service and deal with registration, forgotten passwords, etc. Maybe I want to link to an existing user database, or maybe I want to use something that Azure Mobile Apps doesn’t support – like Weibo (ok – that’s a stretch since I don’t speak Chinese). What then?

Azure Mobile Apps is a pro-dev solution. Pretty much everything is changeable or optional. In this tutorial, I’m going to set up Auth0 as a source. Last time I looked at Auth0, it was being used as a client-flow where the token was swapped for a zumo token. That only works if the identity provider is supported by Azure Mobile Apps. This time, I’m going to integrate custom authentication which isn’t supported by Azure Mobile Apps. To do this, I’m going to get the service to accept the Auth0 identity token rather than swapping the token for a zumo token.

Start by setting up Auth0

I’m going to configure a brand new application in Auth0. Sign into the Auth0 dashboard (you have an account, right?). Click on Apps / APIs, then on the big New App/API and give it a name. Then click over to the Settings tab for the new application.

Screen Shot 2016-03-19 at 7.38.23 PM

Add the mobile URI (which is the auth0 tenant domain followed by /mobile) to the allowed Callback URIs. Next I can set up the authentication – this can literally be anything that Auth0 supports. However, I want custom authentication. I want to be able to allow users to sign up or sign in without having a social media account. In the sidebar, there is a Connections section – click on that, then select the Database option underneath it. Set up the database to allow sign-ups:

Screen Shot 2016-03-19 at 7.42.23 PM

I want to force people to set up a new account, so I removed all the social providers from my application definition in the Connections tab for my application.

Take note of the Auth0 Domain, ClientId and ClientSecret – those will be needed later.

Integrating Auth0 Lock into the Apache Cordova App

I’ve got my Apache Cordova app and I’ve integrated the Auth0 Lock process in plenty of times before – it’s one of my favorite methods to authenticate users. Let’s look at the changes. Most of the changes are in www/js/index.js. First the settings:

    // The ADAL Settings
    //var adal = {
    //    authority: 'https://login.windows.net/common',
    //    resourceUri: 'https://30-days-of-zumo-v2.azurewebsites.net',
    //    redirectUri: 'https://30-days-of-zumo-v2.azurewebsites.net/.auth/login/done',
    //    clientId: 'f35243c4-a4da-4b97-8beb-6a1cf2f76976'
    //};

    var auth0 = {
        clientId: '04pHmxVuhYU1QTDo4lEojLo1sseRLfKG',
        domain: 'shellmonger.auth0.com'
    }

The ADAL code isn’t needed any more, so I’ve just commented it out. The auth0 settings for Client ID and Domain are the only things I need. Don’t specify the client secret. That should never be put in any sort of client code, nor should it ever be checked into a source code repository. It’s, well, secret. Treat it as such.

On to the button logic. I have commented out the entire authenticate() method – it isn’t needed for this functionality. The button handler needs to have the Auth0 lock UI:

        // Set up auth0
        auth0.lock = new Auth0Lock(auth0.clientId, auth0.domain);
        auth0.options = {
            focus: true,
            popup: true,
            rememberLastLogin: true,
            authParams: { scope: 'openid email name' },
        };

        // Wire up the button to initialize the application
        $('#loginButton').on('click', function (event) {
            event.preventDefault();

            auth0.lock.show(auth0.options, function (err, token, profile) {
                console.log(err, token, profile);
            });

            //authenticate(function (data) {
            //    console.log(data);
            //    client.login('aad', { 'access_token': data.accessToken })
            //    .then(initializeApp, function (error) {
            //        console.error(error);
            //        alert('Failed to authenticate to ZUMO!');
            //    });
            //});
        });

As with the ADAL investigation, all I’m doing is logging information at this point – not initializing the application. That comes later.

I will also need to add the Auth0 library to the index.html file. That’s a two step process. Firstly, I need to add the library requirements to the content security policy, and that’s a lot of stuff:

        <meta http-equiv="Content-Security-Policy" content="default-src 'self' data: gap: https://30-days-of-zumo-v2.azurewebsites.net; connect-src https://shellmonger.auth0.com https://30-days-of-zumo-v2.azurewebsites.net; script-src https://cdn.auth0.com https://shellmonger.auth0.com 'self'; style-src https://cdn.auth0.com 'self' 'unsafe-inline'; font-src https://cdn.auth0.com data: 'self'; img-src http://cdn.auth0.com https://www.gravatar.com data: 'self'; media-src *">

This is a complex Content Security Policy – let’s break it down:

Most of these entries are for the Auth0 plugin. I wish Auth0 would use external CSS files so I don’t have to use unsafe-inline, but it is what it is. You can find a great source of information on the Content-Security-Policy website. About the only thing they don’t document is gap: (which is for phonegap/cordova APIs).

Secondly, I need to load the Auth0 Lock library:

        <script type="text/javascript" src="https://cdn.auth0.com/js/lock-8.2.min.js"></script>

Run this project in the Visual Studio Emulator to see the authentication process in progress. The important thing is the data that is logged on the console though. Note that the lock screen is not hidden afterwards – I’ll get to that next. In the console, I get the following:

day-5-pic-1

the important thing is the token. There are some requirements for using 3rd party tokens with an Azure Mobile App:

  • It must follow the Json Web Token format
  • The user Id must be in the subject (sub) field
  • The audience (aud) and issuer (iss) must be known and configured

Head over to http://jwt.io/ and copy your JWT into the Encoded box. The site will decode the JWT for you. Here is mine:

day-5-pic-2

Note that I have a sub field, and the audience and issuer are my Auth0 client Id and domain respectively. Let’s finish off the code on Apache Cordova first, then go configure the server. Here is my button handler:

        // Wire up the button to initialize the application
        $('#loginButton').on('click', function (event) {
            event.preventDefault();

            auth0.lock.show(auth0.options, function (err, profile, token) {
                auth0.lock.hide();
                if (err) {
                    console.error('Error authenticating with Auth0: ', err);
                    alert(err);
                } else {
                    client.currentUser = {
                        id: profile.user_id,
                        profile: profile,
                        mobileServiceAuthenticationToken: token
                    };
                    initializeApp();
                }
            });

As I noted earlier, auth0-lock doesn’t close when it’s finished, so the first thing I do is hide the pop-up. Then I set the ZUMO client.currentUser – the important field here is the mobileServiceAuthenticationToken – this is sent as the X-ZUMO-AUTH string and verified on the server.

Custom JWT Verification in the Server

Now that I have my client in hand, I can work on my server. This is done in two parts. In the Azure Portal, go into your App Service, then All Settings. Go into the Authentication / Authorization blade and turn on the App Service Authentication / Authorization.¬† You don’t need to have any configured services, but the service needs to be turned on.¬†Then go back to All Settings and go to Application Settings. Scroll down to the App Settings section. You need to add an App Setting called Website_Auth_Signing_Key. It is set to the client secret from Auth0.

Note that when you turn off App Service Authentication / Authorization, that isn’t the same as deconfiguration. You can turn it on later and get exactly the same configuration.

day-5-pic-3

Click on Save before leaving the blade. Now, let’s revisit the server code. I need to specify the audience and issuer in the initialization of the azure-mobile-apps SDK:

// Configuration of the Azure Mobile Apps can be done via an object, the
// environment or an auxiliary file.  For more information, see
// http://azure.github.io/azure-mobile-apps-node/global.html#configuration
var mobileApp = azureMobileApps({
    // Explicitly enable the Azure Mobile Apps home page
    homePage: true,
    // Explicitly enable swagger support. UI support is enabled by
    // installing the swagger-ui npm module.
    swagger: true,
    // Authentication settings for custom auth
    auth: {
        audience: '04pHmxVuhYU1QTDo4lEojLo1sseRLfKG',
        issuer: 'https://shellmonger.auth0.com'
    }
});

The audience and issuer must match exactly (including case) what is in the JWT when decoded.

Verifying that the X-ZUMO-AUTH token is working

Since the Authentication / Authorization service is no longer enforcing the X-ZUMO-AUTH token validity, there won’t be any logging to show a bad token. Instead, I need to add some code to log the decoded user during a request. The best place for that is in tables/TodoItem.js – the table controller for the table I am using. Here is my new table controller:

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

// Create a new table definition
var table = azureMobileApps.table();

table.read(function (context) {
    console.log('user = ', context.user);
    return context.execute();
});

module.exports = table;

This is a sneak preview for the next article. All I do is log the user object from the passed-in context. If you’ve followed my articles thus far, you will want to check this code into the master branch and then merge it into the azure branch to deploy it:

git add app.js
git add tables/TodoItem.js
git commit -m "Logging for authentication"
git checkout azure
git merge master
git push

Once you hit the final Enter key, the site will re-deploy. While the service is re-deploying, log onto the Azure Portal and select your App Service, then All Settings, then Diagnostic Logs. You want to turn everything on so you can see what is going on. The blade settings should look like this:

day-5-pic-4

Click on Save, then close the blades for the App Service until you are back at the App Service main blade. Now click on Tools and then Log Stream to see the flow of logs that was just enabled. When the cliet logs in, you should see something similar to this:

day-5-pic-5

This is all the information from the JWT that Auth0 passed in.

One final note

You will note that there is a getIdentity() method on the context.auth – it’s really tempting to use it, but that’s for getting additional information on the Azure App Service Authentication / Authorization users. It won’t work when using custom authentication and it’s likely that your server will return a 500 error if you do use it.

Next Steps

I’ve taken the smallest of peeks into the Node.js table controller today – just enough so I can take a look at the authentication response. I’ll use that next time to turn this application into a multi-user application.

Before next time, I’m going to switch everything back to ADAL authentication with a client auth. That will be the standard authentication scheme going forward. Then, next time I’ll be taking a look at the things we can do with the table controller.

Until then, the code is up on my GitHub Repository.

30 Days of Zumo.v2 (Azure Mobile Apps): Day 4 – ADAL Integration

I went through the process of using Azure AD in a server-based flow in the last article. Sometimes, however, you want to have the native experience. The Facebook Client SDK, for example, deep-links into the Facebook app and allows you to log in without actually entering a username and password – you just click on Approve for the application. Single Sign-on tends to be the big case for using the client-flow. It provides a native experience.

In this tutorial, I’m going to integrate ADAL into my Apache Cordova application and use the token that is provided to authenticate to Azure Mobile Apps.

Note: ADAL is not officially supported on Apache Cordova at this time. If you want to use a platform that is supported, ADAL is supported on native iOS and Android, .NET, Universal Windows Platform and Xamarin. Pick your favorite platform instead. The settings that I configure will be the same irrespective of the platform chosen.

Step 1: Configure a new Native Application in Azure AD

In the prior article, I configured a Web App – actually, Azure AD configured a Web App for me. Unfortunately, that won’t work with ADAL – you need to configure a new Native Application. Log on to the Azure Portal, click on Browse> and then Active Directory – this will get you to the right place in the Classic Portal – right into your default domain on Azure AD. Click on the APPLICATIONS tab.

Screen Shot 2016-03-19 at 1.52.05 PM

Click on the ADD button at the bottom of the window.

Screen Shot 2016-03-19 at 1.52.46 PM

You are developing an application, so the choice is obvious here.

Screen Shot 2016-03-19 at 1.53.31 PM

You can enter any name for the app – I tend to copy the project name. Most important, however, is that you need to select the Native Client Application option before continuing.

Screen Shot 2016-03-19 at 1.55.15 PM

Note that I’ve picked something completely random for the redirect URI. It has to be a valid URI, but it can really be anything. Once you are done, click on CONFIGURE to see the properties you need:

Screen Shot 2016-03-19 at 1.56.07 PM

In order to work with Azure Mobile Apps, we need a little more. Specifically, we need to add the Azure Mobile Apps callback URI to the redirect URI. You can do this by adding it in the box under the Redirect URIs section and then clicking on save. The URI you want to add is:

https://yoursitename.azurewebsites.net/.auth/login/done

Like this:

day-4-pic-3

You will also need to give the native client permission to access the web client. You’ve already set the web client in the last article. Scroll down to the bottom of the CONFIGURE screen and click on the Add Application button:

day-4-pic-4

Click on the dropdown for “Microsoft Apps” and select “All App”, then click on the big tick next to the search box. Your web application will appear:

day-4-pic-5

Click on the plus next to the web application and then click on the tick to continue (in the lower right corner).

day-4-pic-6

Finally, click on Delegated Permissions next to the web application. A short list will drop down – generally only containing an “Access” option. Check the box next to Access. Then click on Save at the bottom of the page.

day-4-pic-7

Yeah – that was as non-obvious as it looks. You will need the Client ID and Redirect URI that you entered later on.

Write some code for Apache Cordova

For reference, writing the code was easy. Getting it to emulate properly was a royal pain in the neck. There are problems with ADAL on iOS 9.x because of a security integration. There are problems running ADAL within Ripple because of a cross-bridge problem. There are problems running ADAL inside the default Android Emulator because one of the returned screens are too big. I was honestly swearing at Apache Cordova at the end of this. However, I finally got it to work using an Android build and the Visual Studio Emulator. Let’s start with the code, which is all contained within the www/js/index.js file:

    // The ADAL Settings
    var adal = {
        authority: 'https://login.windows.net/common',
        resourceUri: 'https://30-days-of-zumo-v2.azurewebsites.net',
        redirectUri: 'https://30-days-of-zumo-v2.azurewebsites.net/.auth/login/done',
        clientId: 'f35243c4-a4da-4b97-8beb-6a1cf2f76976'
    };

The resourceUri is the URI of your app service. The redirectUri is the additional Uri that you added to the Azure AD configuration for your native client application, and the clientId is exactly what you would expect.

        // Wire up the button to initialize the application
        $('#loginButton').on('click', function (event) {
            event.preventDefault();

            authenticate(function (data) {
                console.log('data = ', data);
            });

            //client.login('aad').then(initializeApp, function (error) {
            //    console.error(error);
            //    alert('Failed to login!');
            //});
        });

My first alteration is to throw out the server-flow and use a new function – authenticate() – to do the authentication flow. This has a callback and I just dump what I’ve received. Finally, let’s move on to the actual authentication flow:

    /**
     * Authenticate with the ADAL Plugin
     * @param {function} authCompletedCallback the function to call when complete
     */
    function authenticate(authCompletedCallback) {
        adal.context = new Microsoft.ADAL.AuthenticationContext(adal.authority);
        adal.context.tokenCache.readItems().then(function (items) {
            if (items.length > 0) {
                adal.authority = items[0].authority;
                adal.context = new Microsoft.ADAL.AuthenticationContext(adal.authority);
            }

            // Attempt to authorize user silently
            adal.context.acquireTokenSilentAsync(adal.resourceUri, adal.clientId)
            .then(authCompletedCallback, function (p) {
                // We require user cridentials so triggers authentication dialog
                adal.context.acquireTokenAsync(adal.resourceUri, adal.clientId, adal.redirectUri)
                .then(authCompletedCallback, function (err) {
                    console.error('Failed to authenticate via ADAL: ', err);
                    alert("Failed to authenticate: " + err);
                });
            });
        });
    }

This code won’t actually work – in that the authentication may or may not succeed, but the button won’t go away to be replaced by our app as we normally do. We’ve got more work to do. If you do run this project, however, you can examine the data that comes back:

day-4-pic-1

Note the accessToken – this is the piece that we need to pass into Azure Mobile Apps when we swap it for a ZUMO token. You can also see some great information in this object already. If it isn’t there, you can ask the Azure AD Graph API for more information directly because you have the Azure AD token.

Configure Azure Mobile Apps Authentication

Azure Mobile Apps won’t actually accept this token yet. That’s because the token is being generated for a different application than the one configured. To configure Azure Mobile Apps, we have to go through the Advanced setup. Log on to the Azure Portal and select your App Service from the list of resources. Click on All Settings, then Authentication / Authorization, and finally click on the Azure Active Directory configuration:

day-4-pic-2

Click on Advanced, then enter the Client Id and the Issuer Url. The Client Id is the same one that your app is using. Don’t know the Issuer Url? Well, I don’t blame you. Fortunately, that’s based on your Azure AD tenant, so it’s likely to be correct. However, if you don’t have it and are starting from scratch, you will see it in the data coming back from ADAL (in the userInfo.identityProvider property), or you can get the GUID involved from the Azure AD endpoints – go to the Azure AD configuration screen and click on View Endpoints at the bottom of the window.

More Apache Cordova Code!

Now that we have an access token, we can swap it for the ZUMO token easily:

        // Wire up the button to initialize the application
        $('#loginButton').on('click', function (event) {
            event.preventDefault();

            authenticate(function (data) {
                console.log(data);
                client.login('aad', { 'access_token': data.accessToken })
                .then(initializeApp, function (error) {
                    console.error(error);
                    alert('Failed to authenticate to ZUMO!');
                });
            });
        });

The nice thing about the Visual Studio Emulator is that you can leave it running – the start up is much quicker (compared to, say, the Google Android Emulator). I’m not sure why I wasn’t using it before, except to prove a point. Perhaps the only point I proved was that I like pain.

When you run this project, the authentication flow works and you get your project back.

Next Steps

This was a complex process. I actually tried all the client flows – either in Cordova (Facebook using phonegap-facebook-plugin for example) or in a Xamarin app using the appropriate NuGet packages. Azure AD was by far the most complex setup.

Next time, we’ll take a look at how you can provide a sign-up process using a third-party service instead of the Azure App Service Authentication / Authorization capabilities.

30 Days of Zumo.v2 (Azure Mobile Apps): Day 3 – Azure AD Authentication

In the first two days of my 30 days, I set up my Azure App Service environment – both for local development and cloud deployment. I now have a deployable package and am able to edit the files locally. I’ve also got a modified Apache Cordova application and I’ve deployed that to Ripple – a Cordova emulator that runs in the Chrome browser.

Now, let’s move onto authentication. Azure App Service provides in-built support for five different authentication schemesFacebook, Twitter, Google and Microsoft Account authentication schemes are all considered “social authentication”. Azure AD, on the other hand, is “enterprise authentication”. In addition, you can use the in-built support with either a server-flow (where the service do all the redirects for you in a web-based flow), or client-flow (where you use the client SDK for the identity provider to obtain a token and then swap the token for one that can be used with App Service). If that wasn’t enough, you can eschew the App Service authentication scheme altogther and roll your own with custom authentication. Over the next few blog posts I’m going to take a look at each of these – starting today with a server-based flow.

I find that Azure AD is more complicated than the social authentication providers. With social authentication providers, you use the social provider to set up the OAuth 2.0 flow, get the client ID and secret from the social provider, plug those into the Azure App Service Authentication / Authorization area, and it’s pretty much good to go. There is really good tutorial on this on the Azure Website for each client device.

Azure AD authentication takes a little bit more understanding. You have to set up Azure AD (which most mobile / casual developers don’t have), set up a client, link it into the App Service, then do the client changes. In addition, having Apache Cordova as my client is also complicating things – there are things to understand on this topic as well. So that’s todays task – get an Apache Cordova mobile app working within the Ripple emulator and authenticating to an Azure AD directory.

Step 1: Set up an Azure AD directory

Let’s start with some information about Azure AD. You want a tenant. From the documentation:

In Azure Active Directory (Azure AD), a tenant is representative of an organization. It is a dedicated instance of the Azure AD service that an organization receives and owns when it signs up for a Microsoft cloud service such as Azure, Microsoft Intune, or Office 365. Each Azure AD tenant is distinct and separate from other Azure AD tenants.

Here is the good news. You already have a tenant. In the Azure Portal sidebar, click on Browse> – Active Directory is right at the top. Of course, in a developer subscription, this will not be connected to your enterprise Active Directory instance. It’s standalone. You can create a new directory in the Classic Portal (Click on the big NEW button at the bottom – Active Directory is located under the App Services section). However, I’m going to use my Default Directory for this demo. I have created a new test account – this is a standalone account I’m going to use. To do that, click on ADD USER at the bottom of the page:

Screen Shot 2016-03-18 at 6.11.46 PM

Fill in the account information. Note that you can add information from other tenants – including partner organizations. This is interesting for a number of situations. For example, let’s say you were creating an enterprise mobile app that allowed your customers and employees to interact somehow. You can create a new tenant for the app, then add the employees involved so they can log in. Finally, you can have a sign-up process that adds social accounts to the Azure AD tenant for your customers.

The next page allows you to add information:

Screen Shot 2016-03-18 at 6.22.40 PM

Sorry – I’m not going to cover multi-factor authentication here. That’s a subject for Azure AD. Note that if you do set it up properly, then the multi-factor authentication will work with your mobile application.

Screen Shot 2016-03-18 at 6.23.53 PM

Finally, click on the big green button to create the account and get the temporary password. Make a note of the password – we’ll need it later on before closing out the wizard.

Step 2: Configure Azure App Service

There is a complicated way of configuring Azure App Service to use your Azure AD and a simple way. I like simple. Find your Azure App Service, go into Settings then Authentication / Authorization.

Screen Shot 2016-03-18 at 6.25.57 PM

Turn authentication on, then use the dropdown underneath the toggle to select Allow Request (no action). This is important for a couple of reasons. Firstly, it allows you to control which endpoints need to have authentication and which ones can be accessed anonymously. Secondly, it allows anonymous access features like Swagger UI to continue working. More on Swagger UI in a later article. If you select a specific provider in that dropdown, all requests will cause a 401 Unauthenticated if you have not authenticated – even the ones you specify as anonymous in your application.

Screen Shot 2016-03-18 at 6.35.23 PM

Once you have made those two changes, click on Azure Active Directory to start the configuration process. There is an Express mode and an Advanced mode. The simple / quick mode is Express, so select that.

Screen Shot 2016-03-18 at 6.37.46 PM

Just leave the rest of it alone. Click OK. It will create a new application ID for you, configure Azure AD and then configure the App Service for you. On the way out, click on Save to save your settings.

Testing the connection is simple. Open up a browser and point your browser at https://yoursite.azurewebsites.net/.auth/login/aad – this is the endpoint that initiates a login request. Do this in a private browsing session:

Screen Shot 2016-03-18 at 6.43.44 PM

Note the differing form for the username – this is the “email address” of the test user I created. I used the temporary password that I got given. I’ll have to go through a one-time change-password process. Once that is done, I’ll get a nice banner saying I was successful.

Screen Shot 2016-03-18 at 6.45.42 PM

Note that I’ve not altered the backend code and I won’t be telling the client about the specific Azure AD environment either. That means you can use a test Azure AD tenant for development and move it over to your enterprise production Azure AD tenant when it’s time to go live – without changing any code.

This nice banner is my signal that I’ve set things up properly.

Step 3: Update Apache Cordova to log in

I have a small confession to make at this point. I wanted to go through this entire series without touching my PC. Mac all the way! Why? Because I’ve learned that mobile developers love their macs. I’m honestly not sure why. Developing Apache Cordova apps and using all the facilities that I’ve grown accustomed to within the PC ecosystem – including Visual Studio, Ripple, and
so on – makes developing on a mac painful. I did the development on a PC in
Visual Studio, checked in the code to GitHub and then transferred it to the
mac.

You can get the initial source code from my GitHub Repository at tag day-3-pre.

You may be wondering what the difference is between this project and the regular Zumo Quickstart. Simply put, you have to click a button to get into the app. This becomes very important shortly, because we are going to add a login screen. Before you continue, make sure you can run this project in Ripple. In Visual Studio, this is very easy – just select Ripple (any of the device profiles will do) from the Run… drop-down, and click the Ripple button. On a mac, assuming you’ve got everything set up properly, run ripple emulate.

Adding login code to the Apache Cordova project is easy. Let’s adjust things so that the login button calls the ZUMO login. The code is in the www/js/index.js file:

        // Wire up the button to initialize the application
        $('#loginButton').on('click', function (event) {
            client.login('aad').then(initializeApp, function (error) {
                console.error(error);
                alert('Failed to login!');
            });
        });

Before you run this in Ripple, run this in the Android Emulator. When you click on the button, you will be taken to the same AAD screen flow that you saw when you were testing the AAD setup. It will be slow, but it should work. Now, close that down and start the project in Ripple again and go through the same process.

Firstly, you will notice that Ripple is not REALLY Cordova. It’s really just a locally hosted web service. That has some profound implications for your app. All of a sudden, you have to worry about Cross-Origin Resource Sharing (CORS) – something you don’t need to worry about on a real device. You go through the same flow, but when you get to the end, you get a blank browser window and no amount of teasing will progress you further. You’ve run into an issue that isn’t unique to Ripple or Cordova. Rather it is unique to browser environments where the pages are not being served from the same location as the authentication service. It’s akin to CORS (but not a CORS issue).

You won’t bump into this problem anywhere else EXCEPT Apache Cordova in hosted environments (as opposed to real or emulated devices). You only need to deal with this issue during development on locally running services.

Step 4: Fix the Ripple Issues

To fix this issue, you need to do some more configuration on the App Service. Basically, you need to tell it about your local development environment. First off, let’s look at the Ripple screen:

ripple-1

Note the proxy port there. This is for Ripple. Ripple runs on http://localhost:4400. If you were doing a web service and using a node backend, it may be running on http://localhost:3000, as port 3000 seems like the port to use. If you were using Ionic Live Reload, that lives on http://localhost:8100 by default. Of course, you can change all these numbers, but you will likely know what you have changed them to.

Log onto the Azure Portal and go to your App Service, then All Settings, then CORS (which is under the API menu – you will need to scroll down a bit):

Screen Shot 2016-03-18 at 9.35.33 PM

Enter the URL for your service in the box provided and click on OK. I’m using Ripple, so that’s http://localhost:4400:

Screen Shot 2016-03-18 at 9.37.09 PM

Don’t forget to click on Save, then close the blade. Adding to the CORS list isn’t enough though – you also need to add the local service to the External Redirect URIs list. That’s a little more complex.

Go back to your main app page, then click on Tools and select Resource Explorer.

Screen Shot 2016-03-18 at 9.39.04 PM

Click on Go to launch the resource explorer tool in another tab or window. Expand the config node for your site and click on authSettings:

Screen Shot 2016-03-18 at 9.40.38 PM

This will show you a JSON configuration settings sheet for the authentication blade. The blade provides a UI for managing this, but there is one setting that isn’t managed through the UI – the allowedExternalRedirectURIs – we need to change this:

Screen Shot 2016-03-18 at 9.42.22 PM

Normally, this view is read-only. That’s because you can really screw up your site if you get this wrong. Click on the Read/Write toggle at the top of the screen. That still doesn’t get you in an edit mode, though. So next, click on the Edit button – this will turn into a Cancel button. Finally, you can click into line 14 and make some changes. In this case, I’ve turned the default null into a JSON array with my local development service for Ripple listed. Triple-check that you haven’t made any mistakes before proceeding. When you are sure, click on Put at the top to patch your configuration. You will get a saving spinner and then the changes will be made and the auth service for your site will be restarted. It takes about 10-15 seconds for the restart to be effective.

I recommend closing the Resource Explorer or going back into Read-only mode after you have made the change.

When you test the app within Ripple, it should pop up the same big window, walk you through the process of signing on, and then the authentication window will close and your app will continue on to the actual Todo app list.

Next Steps

There is a lot more to be said on the topic of authentication. We’ve explored just one side of authentication – the server-flow – and talked about some of the pitfalls of developing with Apache Cordova in this case. In the next article, I’ll convert this application to a client-flow to show the difference there.

If you want the final code for this day, you can find it on my GitHub Repository.

Apache Cordova, Azure Mobile Apps and CORS

I am continuing my discovery of Apache Cordova to integrate it into Azure Mobile Apps. This post is about fixing a relatively minor issue. That issue is Cross-Origin Resource Sharing or CORS. One might think this is not an issue with Apache Cordova. After all, a mobile app should be able to access the remote data store with no problem. Where is the CORS issue? The issue occurs in two situations – when using cordova run browser and when using Ripple. In both cases, Apache Cordova starts a server on localhost to serve the pages. The client (the browser session) is pulling the pages from localhost, but retrieving the data from your Azure Mobile Apps service. This hits CORS.

The Server

I’ve got a simple server that is a copy of the basic app from the azure-mobile-apps samples directory. My server looks like this:

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

express.use(morgan('combined'));
var app = new azureMobileApps();

app.tables.import('./tables');
app.tables.initialize().then(function () {
    express.use(app);
    express.listen(process.env.PORT || 3000);
});

I have the following code in the tables/TodoList.js:

var table = require('azure-mobile-apps').table();

table.dynamicSchema = true;

module.exports = table;

You can find the complete code sample at my GitHub repository. I’ve deployed this to an Azure App Service using continuous deployment, linking my App Service to the GitHub repository.

The Client

I’ve adjusted my src/lib/storage-manager.js file as follows:

import uuid from 'uuid';
/* global OData */

export default class Store {
    constructor() {
        console.info('Initializing Storage Manager');

        // We need to add the ZUMO-API-VERSION to the headers of the OData request
        this._defaultHttpClient = OData.defaultHttpClient;
        OData.defaultHttpClient = {
            request: (request, success, error) =&gt; {
                request.headers['ZUMO-API-VERSION'] = '2.0.0';
                this._defaultHttpClient.request(request, success, error);
            }
        };;

        this._service = 'https://ahall-todo-list.azurewebsites.net';
        this._store = `${this._service}/tables/TodoList`;
    }

    /**
     * Read some records based on the query.  The elements must match
     * the query
     * @method read
     * @param {object} query the things to match
     * @return {Promise} - resolve(items), reject(error)
     */
    read(query) {
        console.log('[storage-manager] read query=', query);

        var promise = new Promise((resolve, reject) =&gt; {
            /* odata.read(url, success(data,response), error(error), handler, httpClient, metadata); */

            var successFn = (data, response) =&gt; {
                console.info('[storage-manager] read data=', data);
                console.info('[storage-manager] read response=', response);
                resolve(data);
            };
            var errorFn = (error) =&gt; {
                console.error('[storage-manager] read error=', error);
                reject(error);
            };

            OData.read(this._store, successFn, errorFn);
        });
        return promise;
    }

I’m using DataJS to do the actual call. Note that I’m not going to complete the call in this blog post – I’m just going to get past CORS. I’ve added the package to my npm install:

npm install --save datajs

I’ve also got a Gulp rule to copy the datajs library into my www/lib directory. Check out the GitHub repository to see how that works. I need to include the datajs library into my HTML page as well – that’s just a script reference. Now, let’s run the app and check out the console:

cors-1

The Client Security Policy

There are a couple of places in Apache Cordova where you have to configure content security policies. The content security policy tells Apache Cordova where it can fetch data from. This is configured in two places – one of which is already done for you.

In config.xml, you will note the following line:

    &lt;access origin=&quot;*&quot; /&gt;

This tells Apache Cordova that the app should be able to access data from anywhere. But that isn’t the only place. In your index.html file – and any other HTML file you reference, there is a Content-Security-Policy tag:

        &lt;meta http-equiv=&quot;Content-Security-Policy&quot; content=&quot;default-src 'self' data: gap: https://ssl.gstatic.com 'unsafe-eval'; style-src 'self' 'unsafe-inline'; media-src *&quot;&gt;

Let’s recode this into a friendlier setting:

  • default-src
    • ‘self’
    • data: = Allow loading of local base64 values
    • gap: = Allow JS -> native communication on iOS
    • https://ssl.gstatic.com = Allow Talkback on Android
  • style-src
    • ‘self’ but don’t allow inline styles
  • media-src
    • Anywhere

You can read more about the Content-Security-Policy – it’s very flexible. For now, I need to add my URL to the default-src:

        &lt;meta http-equiv=&quot;Content-Security-Policy&quot; content=&quot;default-src 'self' https://ahall-todo-list.azurewebsites.net data: gap: https://ssl.gstatic.com 'unsafe-eval'; style-src 'self' 'unsafe-inline'; media-src *&quot;&gt;

Handling CORS in Azure App Service

Before this will work, you also need to tell the server to trust your local instance. Log onto https://portal.azure.com and open up your web site. Click on Settings and find the CORS setting:

cors-2

You can enter any URLs you want here. When I run cordova run browser, Apache Cordova will start a server at http://localhost:8000:

cors-3

Don’t forget to save your changes once you are done.

Wrapping Up

Once you have done these changes, you can try the project again. This time the pre-flight connection will succeed. The actual transfer will succeed but the data decoding will not work. That’s because I haven’t finished writing the code for utilizing data.js as yet. That, however, is a blog post for another time.

An Asynchronous Task List in Apache Cordova

I’ve been spending a bunch of time recently learning Apache Cordova with an eye towards integrating something within Azure Mobile Apps. I want to have an iOS and Android app that works with my TodoItem backend in Node. I also want it to be written in ES2015. So far, I’ve done a bunch of the basic work, but now it’s time to put an app together. You can see most of the work on my GitHub repository.

What I want to consider today is an asynchronous task list store. Each task in the TodoItem has an ID (which is a GUID converted to a string), a text description and a completed flag. I need to be able to read, insert and update records. I’m not going to deal with deletions right now, but that’s coming. To abstract this, I’m going to write an ES2015 class. Let’s start with the basics:

import uuid from 'uuid';

export default class Store {
    constructor() {
        console.info('Initializing Storage Manager');
        
        this._data = [
            { id: uuid.v1(), text: 'Item 1', complete: false },
            { id: uuid.v1(), text: 'Item 2', complete: false }
        ];
    } 
}

I’m creating two example tasks to get me started. I don’t need them, but it helps to show off the HTML coding.

At the center of asynchronous programming in JavaScript is the Promise. Put simply, a promise is a representation of something that doesn’t exist yet. It will be asynchronously resolved and your code can come back to it later. You can use promises relatively simply:

asyncFunction
   .then((result) => {
      /* do something with the result */
   }).catch((error) => {
      /* do something with the error */
   });

You can chain multiple promises and wait for multiple promises to complete. This all results in a rather flexible mechanism to make your code asynchronous. But how do you create a promise? My Store class has an array right now. I want to make it ACT asynchronously so that I can add the network code later on. You need to write a method that either resolves or rejects the promise. Here is the insert() method:

    /**
     * Insert a new object into the database.
     * @method insert
     * @param {object} data the data to insert
     * @return {Promise} - resolve(newitem), reject(error)
     */
    insert(data) {
        data.id = uuid.v1();
        console.log('[storage-manager] insert data=', data);
        var promise = new Promise((resolve, reject) => {
            // This promise always resolves
            this._data.push(data);
            resolve(data);
        });
        
        return promise;
    } 

Creating a promise is a case of creating a new Promise object with a callback function. The callback will be passed “what to call when you are resolving or rejecting the promise”. You then do your processing and call the resolve or reject method to say “I’m done”. Note that I’m using “fat-arrows” to preserve the this variable value. If you don’t use a fat-arrow function then you have to preserve this by other means. All my other functions are similar. For example:

    /**
     * Read some records based on the query.  The elements must match
     * the query
     * @method read
     * @param {object} query the things to match
     * @return {Promise} - resolve(items), reject(error)
     */
    read(query) {
        console.log('[storage-manager] read query=', query);
        var promise = new Promise((resolve, reject) => {
            var filteredData = this._data.filter((element, index, array) => {
                for (let q in query) {
                    if (query[q] !== element[q]) {
                        return false;
                    }
                }
                return true;
            });
            resolve(filteredData);
        });
        
        return promise;
    }  

This will return a list of tasks that match my criteria.

Using this class is encapsulated in my index.js code:

app.on('deviceready', function () {
    var taskStore = new Store();
    
    // Get the various pieces of the UX so they can be referred to later
    var el = {
        todoitems: document.querySelector('#todo-items'),
        summary: document.querySelector('#summary'),
        refreshlist: document.querySelector('#refresh-tasks'),
        addnewtask: document.querySelector('#add-new-task'),
        newitemtextbox: document.querySelector('#new-item-text')
    };
    
    // This is called whenever we want to refresh the contents from the database
    function refreshTaskList() {
      el.summary.innerHTML = 'Loading...';
      console.log('taskStore = ', taskStore);

      taskStore.read({ complete: false }).then((todoItems) => {
          console.log('Read the taskStore: items = ', todoItems);
          let count = 0;
          el.todoitems.innerHTML = ''; 
          todoItems.forEach((entry, index) => {
              let checked = entry.complete ? ' checked="checked"': '';
              let entrytext = entry.text.replace('"', '&quot;');
              let html = `<li data-todoitem-id="${entry.id}"><input type="checkbox" class="item-complete"${checked}><div><input class="item-text" value="${entrytext}"></div></li>`;
              el.todoitems.innerHTML += html;
              count++;
          });  
          el.summary.innerHTML = `<strong>${count}</strong> item(s)`;  
      }).catch((error) => {
          console.error('Error reading task store: ', error);
          el.summary.innerHTML = '<strong>Error reading store.</strong>';
      });
    }

    // Set up the event handler for clicking on Refresh Tasks
    el.refreshlist.addEventListener('click', refreshTaskList);
    refreshTaskList();
    el.newitemtextbox.focus();
});

Note the highlighted line. I call the read() method (above) and wait for it to return the value. This can be asynchronously. Once it completes, the results are passed into the fat-arrow function in the then clause and that renders the list of tasks for me.

The changes to this version are quite extensive, so I encourage you to check out the code at my GitHub Repository. All the ES2015 code is in src/js with the store implementation in src/js/lib/storage-manager.js.

I still have some work to do here. Specifically, I copied (and updated) the Azure Mobile Services Quick Start for Apache Cordova and ES2015. I want to update the CSS3 code to be a little more friendly towards the devices. I also want to implement sorting and filtering. That’s the topic for another blog post.