Authentication for Cloudant Envoy Apps, Part II

Make Your App Offline First

In the first part of this series about building a Cloudant Envoy application that uses Facebook to provide authentication, I showed you how to:

  • Create a Facebook developer application to provide us with a client_id and client_secret auth codes.
  • Use PassportJS to perform most of the work of bouncing the browser between our app and Facebook while the user logs in.
  • Use Cloudant Envoy to serve out our static content and the Passport code, as well as its main function of behaving as middleware that our client-side application will replicate with.
  • Use time-limited, single-use tokens to transmit the Envoy credentials from the server to the client.

All of the above is just a means of serving out your content and maintaining the database of users. The work of creating your app itself is still to do and can be treated as a separate exercise: the client side code (reading and writing from its local data store) can be built independently and can be plugged into the main framework at the last minute.

Audiomark is a Progressive Web App

The app I am building is called Audiomark. The idea for it came from a conversation with a friend of mine who is a schoolteacher. Like most teachers, he grades a lot of written work usually by handwriting comments into each of his students’ books. He wanted a means of recording audio snippets, printing out a QR-code on his label printer and then sticking the label to the book — saving himself the labour of writing so many comments by hand.

Assemble the open-source projects

The client-side code needs to record audio in a web page, store it offline and then sync it to Cloudant Envoy. Here are the technologies I chose:

  • PouchDB provides a common storage API on a range of browsers. It will happily sync directly to Cloudant or via Cloudant Envoy.
  • MSR provides cross-browser audio recording. Unfortunately, Safari doesn’t support the web API that this library relies on, so Apple devices are left out.
  • QRCode.js allows a string to be encoded as a QR-code on the client side. Initially I called out to a web-based API but this library allows the whole process to be undertaken on the client side.
  • MaterializeCSS provides a framework for creating mobile-friendly HTML markup.

How does it work?

Assuming you’ve logged into the application via Facebook, then a local PouchDB database is created which is set to sync with Envoy in one direction: client to server. Any new data that is added to the PouchDB database will be synced to Envoy and from there to Cloudant. It doesn’t matter if you happen to be offline or have a poor network connection—you can continue to record audio and print QR codes.

After the page loads, the microphone icon becomes clickable. When you click the microphone icon a 20-second (maximum) audio clip is recorded. You can halt the recording at any time by clicking the icon again. At the end of the recording the MSR library sends us a binary blob object that represents the WAV file we have just recorded. How can we store binary blobs offline? Fortunately PouchDB can store binary data as attachments to the JSON documents it normally stores. It’s simple:

function saveBlob(blob) 
var id = genid();
var doc = {
_id: id,
ts: new Date().getTime(),
_attachments: {
'audio.wav': {
content_type: blob.type,
data: blob
}
}
};
return db.post(doc);
});

We are generating our own database IDs here because we want to keep the ID size small. The ID will form part of the URL that gets turned into a QR code — the longer the URL, the more detailed the image needs to be.

Once we’ve generated our ID, we know what the URL is going to be so we can go ahead and generate the QR code:

var url = location.origin + '/w/' + userid + '/' + id;
qrcode.clear();
qrcode.makeCode(url);

It’s worth noting here that, although we have set the PouchDB database to sync to the cloud, we have no idea whether the data has reached the server yet; however, it doesn’t prevent us from printing the QR code containing the URL. As long as the data is synced before the student scans the QR code, then all will be fine. It would be perfectly fine to take your laptop and printer to a remote location, record numerous clips, print out multiple labels and then sync with the cloud when you return home. That’s the advantage of an Offline First approach — 100% up time, even when there’s limited or zero network connectivity.

When a clip is recorded it can be printed by hitting the print icon. The CSS for the print output hides everything but the hidden QR code.

Clicking the done button sets Audiomark up to prepare for another recording.

The PWA benefits

As this app is built as a Progressive Web App (PWA), it can offer benefits to modern browsers that support the newest APIs. If Service Workers are supported, the app caches its assets offline so the site can reload with no network connection. The app scales visually to work on mobile and tablet form-factors and is easily added to a phone’s home screen. The data is stored on the device using PouchDB, and the QR codes are generated client-side so the app is completely self-contained.

My Audiomark application in action

Try it yourself!

You can try Audiomark for yourself at https://audiomark.mybluemix.net.


This post was Part II of the “Authentication for Cloudant Envoy Apps” 3-part series. You can review Part I, which covers building a static application that writes data locally using PouchDB. There, you’ll also learn to use Cloudant Envoy to store user data and how to use PassportJS to handle authentication via Facebook. Now that you’ve made your application Offline First in Part II of the series, check out Part III, where I walk through how to add Twitter authentication to your app.