Meteor.js Tutorial — Integrate Duo Multi-Factor Authentication

Stephen Richardson
7 min readSep 28, 2016

--

Protecting your data is very important. Adding multi-factor authentication to your logon process is a great addition to your security strategy. While you can build out your own basic system utilizing a code sent via email, or using an SMS api directly, most companies’ needs have gone beyond this. Features such as enhanced reporting, user & device management, security policies and integration with their existing app ecosystem are the new norm. Duo provides a great product and it’s basic version is free to use for up to 10 users.

Why not build out your own auth service or take advantage of the available Google Auth etc. with Meteor? While those are good options, they simply don’t offer the control and feature set that Duo provides out of the box. Here are just a few:

IP whitelisting/blacklisting, offline bypass codes, one time use/time expiring bypass codes, denying access based on device, browser, OS version — even client java/flash version, security groups with varying levels of access, AD/LDAP integration, hardware key support, native apps for IOS/Android/Windows Phone/Blackberry, self-service device management portal..

If those features are important to you, it may make sense to use a more advanced MFA platform such as Duo. The below tutorial could also be modified for a multi-tenant type app to store the Duo integration keys in a database and allow the client admin to manage their own Duo integration within the UI.

Note — This tutorial will quickly go over the basics to integrate Duo with Meteor.js. It will be using Meteor 1.4.1.1 with Blaze. There are most likely better ways to code any part of this, I wanted to release the basic steps since there aren’t many multi-factor auth resources for Meteor available. I will continue to update this post as the ux/features get built out.

Setup Duo

  1. Signup for a Duo account, set yourself up as an admin, and download the Duo app from the IOS/Android app store so you can test all of the features. Add your mobile number so you can test the phone call/sms auth features.
  2. Once logged into the admin panel, add a new Web SDK Application. Document the Integration Key, Secret Key and API Hostname and add them to your Meteor settings.json file for later. Don’t change too many defaults, just give it a name, use ‘None’ for username normalization.
Choose the Web SDK type.

4. Setup a user. You’ve set yourself as an admin, but that’s to manage Duo. You’ll need to add yourself as a user separate from your admin user. You can use the same phone/email settings. For the username, enter an email address since that’s the default username format for Meteor. Add your phone and send yourself an invite text/email so you can easily activate in your Duo app.

Match the Meteor user email address, Meteor default: Meteor.user().emails[0].address

Add new users — email address format for username

5. Verify in the Duo Application/User settings that you have given the new user access to the application. If you haven’t, after the user authenticates they will see options to configure themselves as a new user if your Duo settings allow it or an unauthorized access error message in the Duo iframe.

Important Note For this initial version, we will be adding the Duo auth component directly to Meteor, and not integrating it into the actual login flow. This will allow you to setup the different components and get familiar with the login and routing flow quickly. This will assume you have your app configured with accounts-password or another system and you are currently logged in as a user, with a valid Meteor.user()/id.

Configure Meteor

  1. Add the Duo Integration Key, Secret Key and API Hostname from your application settings in the Duo admin portal. The aKey (Application Key) is just a random key you create. The host (api hostname) is not needed on the server, I included it for now for documentation. The below would be accessed (example) Meteor.settings.services.duoSecurity.ikey

From DuoYour akey is a string that you generate and keep secret from Duo. It should be at least 40 characters long and stored alongside your Web SDK application’s integration key (ikey) and secret key (skey) in a configuration file.

Example settings file at: (project root)/settings.json

{
“services”: {
“duoSecurity”: {
“sKey”: “xxx”,
“iKey”: “xxx”,
“host”: “xxx”,
“aKey”: “xxx”
}
}
}

2. There are several ways to get the source files you will need from Duo. I’m doing the most basic to shorten this article. Bookmark the Duo NodeJS library on Github or NPM. Add the library to your Meteor app:

> meteor npm install duo_web --save

3. The client side auth flow and interaction are handled within an iframe handled by a single file provided by Duo, Duo-Web-v2.min.js. To shorten this article, we will download the source file and place it directly on the client so that it loads by default. Download the source and put it in your project in the special Meteor compatibility directory:

(project root)/client/compatibility/Duo-Web-v2.min.js

Note — better to use import/require and control the scope & load order of the client side library. Also, I noticed the Github project included v2 and the npm library has the v1 named version.

Meteor Server Side Setup

  1. Create a file at a server-side path, and copy the below Gist. You will need to update the duoSettings variable to assign your ikey, skey, host, and akey as you have them.
(project root)/server/methods/duo.js

Note — I’m using more error checking within this code, mostly for example of what’s important. I’m also being slightly more wordy to ensure certain variables or methods are available before executing them. I recommend using the newer validated method format and breaking parts of this code out as classes/modules.

Meteor Client Side Setup

  1. Create a folder on the client and two files like below. Create a basic route to load the template as you would for any page.
(project root)/client/templates/duo/auth_frame.html
(project root)/client/templates/duo/auth_frame.js
Basic route example using FlowRouter/BlazeLayout

2. You will need to have an iframe component to load the Duo client library. Within this iframe, Duo will interact with the user as needed to manage their devices and select authentication options such as Push, SMS, Phone Call etc. This is an example of the iframe loaded:

3. auth_frame.html will be a simple template to hold the iframe, I’m using Semantic-UI in this example. The css is inline only for this example, following the Duo integration docs for the iframe. With the combination below, the page is responsive and works with desktop/mobile. At a minimum you need:

<iframe id="duo_iframe"></iframe>

4. auth_frame.js will hold the basic logic and js needed to process the login request and render the iframe properly. You will need to update the below code in two main areas:

  • Line 38, Your API Hostname (host) in Duo.init()
  • Line 21, The desired path for redirecting after a successful login.

The onRendered will take the current user and call the server to generate a signed request and when it’s received, will initialize and display the iframe to the user.

Note — This is mainly using the logic/example from the Duo integration docs, you can handle this flow many ways. The submit_callback could also be a function that submits the form and you could handle with a normal Template.xx.events submit event.

Testing

  1. Start Meteor, be sure to load settings.json and be sure you are logged into your app as a normal Meteor user. The Meteor user email address needs to match exactly the username/email address for the user added in Duo Admin → Users at the beginning of this article.
  2. Visit the route path that will load the auth_frame.html template.
  3. If everything works, you will see the Duo auth iframe:

4. If you see a setup screen to activate a new user, it probably means the currently logged in user’s email does not match the address for the user you created in Duo. Make sure you are using the application user address and not the Duo Admin user (they can be the same address). You can try to go through the new user setup, but you will need to approve the user for the app if you have disabled new user on-boarding etc in Duo. Example error:

5. All of the auth features should work, such as Push (easiest), SMS, Phone Call, Bypass/Offline codes etc. See Duo docs for more auth methods.

6. Once you have authenticated successfully, you will be redirected to the route you configured in the submit callback in auth_frame.js. Check the console for any errors. To test multiple times, just refresh your browser to reset the state of the Duo js client component, and revisit your route for auth_frame.html. You can test it multiple times to get familiar with Duo.

Part 2 will go over integrating with the actual logon flow and securing the different components.

--

--