Authentication for Cloudant Envoy Apps, Part I

Adding Facebook Authentication

--

For those familiar with the Apache CouchDB ecosystem, Cloudant Envoy is a microservice that serves out your static application and behaves as a replication target for your one-database-per-user application. Simply build an application that writes data locally using PouchDB or Cloudant Sync, and Envoy will ensure that each user’s data is stored in a single Cloudant database, with each user’s data carefully segregated.

For more background on Cloudant Envoy, I have a write-up over on Offline Camp:

So far I’ve been looking at Envoy apps that have been generating their own users. Save a document in the envoyusers database, and Envoy will use that information for subsequent authentication requests. But what if you want users to sign up with Facebook/Google/Twitter/etc? How can Envoy integrate with social media’s federated login?

Before we move on, let’s review the prerequisite knowledge needed to benefit from this post. I’m going to show you how to deploy a live application to a Cloudant server and add the ability to use Facebook authentication so that your users can sign up for your service with Facebook. I’m going to assume you know a fair amount about JavaScript to be able to write the necessary Express routes to complete this task.

Now back to the task at hand: How can we allow our users to sign up for our application with Facebook?

Passport to the rescue!

http://passportjs.org/

Luckily the PassportJS project solves 95% of the problem for us. It has a number of modules, each handling authentication for a third-party partner. Although Envoy doesn’t use Passport out-of-the box, you can create an Envoy app that does. Here’s how.

Create a Facebook app

We’re going to use Facebook as an example. Visit the Facebook Developers portal and create a new app in your account. You will need to supply the name of your app, its URL and other sundry details. I found that Facebook was reluctant to accept localhost as a valid domain name, so I added a line to my /etc/hosts file:

I then used mypretenddomain.com as my app’s domain.

After filling in the form, Facebook will issue you with a CLIENT_ID (or app ID) and a CLIENT_SECRET (or app secret), which you will need to take note of for your code later on.

Create an Envoy app

Now we’ll walk through how to create an Envoy app. In a new directory, type npm init and make sure to follow the on-screen prompts. This will create a template package.json file for you. Then we can add the modules we’re going to need for this project:

Create some static content:

The layout of an Envoy app is pretty simple. First create an app.js file:

Once you’ve saved that file in the project directory you can then run the app:

Note: Envoy assumes the Cloudant URL will be in a COUCH_HOST environment variable. Replace myusername, mypassword and myhost with your own Cloudant account details.

We now have a web server serving out our own static content, which also acts as a replication target for PouchDB/CouchDB/Cloudant/Cloudant-Sync clients.

Add Facebook authentication

We’ll need some extra modules to handle Facebook authentication:

Then we need to add some custom endpoints into our app to handle the authentication process.

  • GET /_facebook — Hitting this endpoint in your browser will bounce the user to Facebook and ask them to authenticate.
  • GET /_facebook/callback — After logging into the Facebook website, it will bounce the browser to this URL to allow us to access the user’s profile.

We implement a getOrCreateUser function, which checks if Envoy knows about this user already. If not, a new user is created.

Envoy’s user model is very simple: add a document to its users database (default name envoyusers) to allow someone to replicate. Envoy provides some helper functions for you:

  • envoy.auth.getUser(userid, callback) — to fetch a user by userid
  • envoy.auth.newUser(userid, password, metaobject, callback) — to create a new user

We need to run the app, passing in our app’s CLIENT_ID and CLIENT_SECRET environment variables we got when we created the Facebook integration:

Here’s the source code:

How do we communicate the user credentials to the client side?

We know the ID and password of our user — not the Facebook username and password—the Envoy username and password. But how can we send that data to the client side? A simple way is to bounce the browser to a URL with the credentials in the query string:

We could write some client-side JavaScript to parse the query string, extract the username and password and store it locally.

A safer way would be to create a single-use token and pass that in the query string.

In this case the client-side code needs to extract the token, make a call back to the server to exchange the token for the username and password and then store the credentials locally. This is more secure as the token can be made to expire on use and have a built-in time limit.

Here’s some simple client-side code to extract and decode the token, ultimately saving the user details in a local PouchDB document. Local documents are never transmitted during replication; they only remain on the device they are created:

Making your app

Now the client side app has the Envoy credentials (in a PouchDB document whose ID is _local/user), we can set about building an app that reads and writes data to its local PouchDB database and replicates its data to and/or from your Envoy service using the credentials provided.

https://developers.facebook.com/

If you’ve followed along to this point, then you’ve built a static application that writes data locally using PouchDB, and you’ve used Cloudant Envoy to store user data in a Cloudant database. Using PassportJS to handle authentication, your users can now sign up to use your app using their own Facebook credentials. Next, check out Part II of this series, where we’ll see how to make an Offline-First app with Cloudant Envoy using the tools we’ve built here:

--

--