Duo Web Example
Jon Phenow edited this page Nov 16, 2015
·
3 revisions
Duo's overview is a good place to start. Here's how I'd explain it in words:
- Login your user as you normally would and redirect to a new endpoint (like
<your-app>/auth/duo
) - In this new endpoint:
- Using Duo-Api, sign an identifier, like a username, into what Duo calls the
sig_request
- Render a page using their iframe and js framework and fill in the sig_request param as well as any other options you need to
- Using Duo-Api, sign an identifier, like a username, into what Duo calls the
- The User goes through a 2 factor handshake, upon success:
- Handle a POST back to this same endpoint from above (can also be configured to be a different endpoint when initializing the js library)
- In this post, use Duo-Api gem to unpack the response and verify that the identifier matches the current-user's identifier in your system
Note that this gem doesn't discriminate against things like Sinatra or vanilla services, this is just an example and should be somewhat applicable to other frameworks. Find the necessary js framework here. The bundled version doesn't require jQuery
, we'll use that for this example.
# config/initializers/duo-api.rb
DuoApi.config do |config|
config.hostname = "xxxx-duosecurity.com"
config.integration_key = "asdf"
config.secret_key = "asdf"
config.app_secret = Rails.application.secret_token
end
# in routes
get "/auth/duo", :to => "DuoController#duo"
post "/auth/duo", :to => "DuoController#duo_callback"
# Controller
class DuoController < ApplicationController
before_filter :authenticate!
def duo
@signed_request = DuoApi.sign(current_user.login)
end
def duo_callback
if current_user.login == DuoApi.verify(params[:sig_response])
current_user.update_attributes(:duo_verified_at => Time.now)
redirect_to "/"
else
flash[:error] = "Could not authenticate you with Duo"
redirect_to login_path
end
end
end
<%# duo.html.erb %>
<html>
<head>
<script src="/javascripts/Duo-Web-v1.bundled.min.js"></script>
<script>
Duo.init({
'host': '<%= DuoApi.config.hostname %>',
'sig_request': '<%= @signed_request %> '
});
</script>
</head>
<body>
<iframe id="duo_iframe" frameborder="0"></iframe>
</body>
</html>
Some of the controller code makes assumptions about what an app might have available to it. Also note that it stores a duo-verified timestamp. One could imagine using this to force-re-duo-auth after a window of time. Likely, in practice, you wouldn't want this in your regular database, and instead in a session or something.