Salesforce OAuth2 authentication with Active Admin

Here’s a quick and dirty guide to get OAuth2 authentication working for Active Admin using the Salesforce strategy.

Instructions

Add the omniauth gem to your Gemfile and run bundle install.

# Gemfile

gem 'omniauth-salesforce'

Configure devise to use the Salesforce strategy for omniauth.

# config/initializers/devise.rb

require 'omniauth-salesforce'
config.omniauth :salesforce, ENV["SFDC_CLIENT_ID"], ENV["SFDC_CLIENT_SECRET"]

Add :omniauthable to the devise call in the AdminUser model and add a class method for retrieving the admin user based on the oauth access token.

# app/models/admin_user.rb

class AdminUser < ActiveRecord::Base
  devise :database_authenticatable, :omniauthable,
         :recoverable, :rememberable, :trackable, :validatable
  
  def self.find_for_salesforce_oauth(access_token, signed_in_resource=nil)
    data = access_token.extra
    if admin_user = AdminUser.where(:email => data.email).first
      admin_user
    else
      AdminUser.create!(:email => data.email, :password => Devise.friendly_token[0, 20])
    end
  end
end

Add an omniauth controller to the devise_for call in the routes file.

# config/routes.rb

devise_config = ActiveAdmin::Devise.config
devise_config[:controllers][:omniauth_callbacks] = 'admin_users/omniauth_callbacks'
devise_for :admin_users, devise_config

Add a controller to handle the omniauth callback.

# app/controllers/admin_users/omniauth_callbacks_controller.rb

class AdminUsers::OmniauthCallbacksController < Devise::OmniauthCallbacksController
  def salesforce
    @admin_user = AdminUser.find_for_salesforce_oauth(auth_hash, current_admin_user)

    if @admin_user.persisted?
      flash[:notice] = I18n.t "devise.omniauth_callbacks.success", :kind => "Salesforce"
      sign_in_and_redirect @admin_user, :event => :authentication
    else
      session['devise.salesforce_data'] = auth_hash
      redirect_to new_admin_user_registration_url
    end
  end

  def auth_hash
    request.env["omniauth.auth"]
  end
end

Override the Active Admin login page in your application and add a link to sign in using Salesforce.

# app/views/active_admin/devise/sessions/new.html.erb

<div id="login">
  <h2><%= title "#{active_admin_application.site_title} Login" %></h2>
  <div class="oauth_providers" style="margin-top: 40px;">
    <%= link_to 'Sign in with Salesforce', admin_user_omniauth_authorize_path(:salesforce) %>
  </div>

  <% scope = Devise::Mapping.find_scope!(resource_name) %>
  <%= active_admin_form_for(resource, :as => resource_name, :url => send(:"#{scope}_session_path"), :html => { :id => "session_new" }) do |f| 
    f.inputs do
      Devise.authentication_keys.each { |key| f.input key, :input_html => {:autofocus => true}}
      f.input :password
      f.input :remember_me, :as => :boolean, :if =>  false  #devise_mapping.rememberable? }
    end
    f.buttons do
      f.commit_button "Login"
    end
  end
  %>

  <%= render :partial => "active_admin/devise/shared/links" %>
</div>