Using Duo MFA with Devise for Rails
Roll your own two-factor authentication solution
Turns out, I was wrong. (It’s almost 2019, for crying out loud!)
Here, I’ll try and help fix that.
Credit where it’s due
Actually, this post by TJ Oyeniyi did end up proving very useful, but it’s behind a paywall, and you can’t copy/paste the code. So I figured presenting some similar information for free, with my own spin, and in an easier-to-copy format, would be worthwhile. (But still, maybe thank him if you can.)
Okay, setting up…
First things first. Install the Duo gem:
gem install duo_web. Or put it in your Gemfile:
gem 'duo_web'. Then set some environment variables, either in your
.env file or as Heroku config vars or whatever.
DUO_INT_KEY=your_identity_key_from_duo DUO_SECRET_KEY=your_secret_key_from_duo DUO_APP_KEY=your_secret_string # Generate with SecureRandom.gen_random(40)
To handle the actions, create a
RegistrationsController that inherits from your
Devise::RegistrationsController and add the following:
class RegistrationsController < Devise::RegistrationsController
skip_before_action :require_no_authentication, only: [:verify_duo]
@sig_request = Duo.sign_request(ENV["DUO_INT_KEY"], ENV["DUO_SECRET_KEY"], ENV["DUO_APP_KEY"], current_user.email)
@authenticated_user = Duo.verify_response(ENV["DUO_INT_KEY"], ENV["DUO_SECRET_KEY"], ENV["DUO_APP_KEY"], params['sig_response'])
session[:duo_authentication] = true
ApplicationController you can check to see if the
session[:duo_authentication] variable is set.
You can invoke this method from any individual controller. Or you can require it for all controllers by putting the following at the top of your
Assuming you’ve already got Devise routes up and running, just include a few more lines to the relevant controller actions, above.
devise_scope :user do
post 'registrations/verify_duo', to: 'registrations#verify_duo', as: :verify_duo
get 'registrations/connect_with_duo', to: 'registrations#connect_with_duo', as: :connect_with_duo
root :to => "registrations#connect_with_duo"
The last thing you’ll have to do is allow a user to actually use the Duo setup. For that you’ll need a view corresponding to your controller action; in this case, at
You’ll need to stylize your iframe to work with your app (setting
min-height most importantly).
You can easily determine where and when the Duo connection setup takes effect. If you’re working with users in an existing app and want them to configure Duo for the first time, that’s possible, too. Playing with the
after_sign_in_path_for(), and the routes are all that’s required.
This setup also works with Duo Access Gateway, which makes it easy to tap into existing directory credentials for things like Microsoft Active Directory or Google Apps with SAML.
The whole thing
Here’s a gist of the whole thing. Enjoy!