Go back to the main page

Get started integrating Rails 4 and QuickBooks Online with the Quickeebooks Gem: Part 4 : Implementing Single Sign On.

 

Part 4: Implementing Single Sign On for a Rails app.

  1. Install devise for authentication
    • Add gem 'devise' in Gemfile and run bundle install
    • Run rails g devise:install on command line
    • Modify config/environments/development.rb
    •   config.action_mailer.default_url_options = { host: 'billtastic.dev' }
          
    • Modify config/routes.rb with root to: 'vendors#index'
    • Billtastic::Application.routes.draw do
        resources :vendors
        resources :quickbooks do
          collection do
            get :authenticate
            get :oauth_callback
            get :disconnect
          end
        end
        root to: 'vendors#index'
      end
      
    • Create a Devise user.
    •   rails g devise user
        bundle exec rake db:migrate
      
    • Add sign up code to the app/views/layouts/application.html.erb
    •   <section id="sign-in">
          <% if user_signed_in? %>
              Signed in as <strong><%= current_user.email %></strong>.
            <%= link_to 'Edit profile', edit_user_registration_path %> |
            <%= link_to "Sign out", destroy_user_session_path, method: :delete %>
          <% else %>
            <%= link_to "Sign up", new_user_registration_path %> |
            <%= link_to "Sign in", new_user_session_path %>
          <% end %>
        </section>
      
    • Issue a touch tmp/restart.txt to reload Rails.
    • Refresh billtastic.dev/vendors and you will see a basic sign in implementation
      Note: Styling code, which is very minimal, will not be included in the tutorial. See the source instead.
  2. Add the "Sign on with Intuit" button.
    • Add the omniauth-openid gem to the Gemfile and bundle install.
    • Modify config/initializers/devise.rb with the following:
    • require 'openid/store/filesystem'
      Devise.setup do |config|
        # ommited ....
        # Insert this next line down in the Omniauth section
        config.omniauth :open_id, :store => OpenID::Store::Filesystem.new('/tmp'), :name => 'intuit', :identifier => 'https://openid.intuit.com/openid/xrds', :require => 'omniauth-openid'
      
    • Modify app/models/user/rb:
    • class User < ActiveRecord::Base
        # Include default devise modules. Others available are:
        # :confirmable, :lockable, :timeoutable and :omniauthable
        devise :database_authenticatable, :registerable,
               :recoverable, :rememberable, :trackable, :validatable,
                        :omniauthable, :omniauth_providers => [:intuit]
               
                 def self.find_for_open_id(access_token, signed_in_resource=nil)
                   data = access_token.info
                   if user = User.where(:email => data["email"]).first
                     user
                   else
                     User.create!(:email => data["email"], :password => Devise.friendly_token[0,20])
                   end
                 end
      end
      
    • Create a new file app/controllers/users/omniauth_callbacks_controller.rb:
    • class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
        skip_before_filter :verify_authenticity_token, :only => [:intuit]
      
        def intuit
          @user = User.find_for_open_id(request.env["omniauth.auth"], current_user)
      
          if @user.persisted?
            flash[:notice] = I18n.t "devise.omniauth_callbacks.success", :kind => "Intuit"
            sign_in_and_redirect @user, :event => :authentication
          else
            session["devise.intuit_data"] = request.env["omniauth.auth"]
            redirect_to new_user_registration_url
          end
        end
      end
      
    • Modify the Devise users route in config/routes.rb to:
    • Billtastic::Application.routes.draw do
        devise_for :users, :controllers => { :omniauth_callbacks => "users/omniauth_callbacks" }
        # ommitted
      
    • Add "Sign on with Intuit" button to app/views/layouts/application.html.erb.
    •   <!-- omitted .. -->
            <%= link_to "Sign up", new_user_registration_path %> |
            <%= link_to "Sign in", new_user_session_path %> | 
            <ipp:login href="<%=
            user_omniauth_authorize_path(:intuit) %>"></ipp:login>
          <% end %>
      
    • Issue a touch tmp/restart.txt to reload Rails.
    • Refresh billtastic.dev/vendors and you will now see the official Intuit Sign On button.
  3. Automatically authenticate with the QBO API after signing on with Intuit.
  4.   <!-- app/views/layouts/application.html.erb -->
      <!-- ommited.. -->
      <script type="text/javascript" src="https://appcenter.intuit.com/Content/IA/intuit.ipp.anywhere.js"></script>
      <!-- configure the Intuit object: 'grantUrl' is a URL in your application which kicks off the flow, see below -->
      <script>
          intuit.ipp.anywhere.setup({menuProxy: '/path/to/blue-dot', grantUrl: '<%= authenticate_quickbooks_url %>'});
        <% if user_signed_in? && !session[:token] %>
            intuit.ipp.anywhere.directConnectToIntuit();
        <% end %>
      </script>
    </body>
    
    Discussion: Even though we are using Intuit's authentication to sign into our Rails app we still need to "connect" to QuickBooks to integrate with the QBO API. The directConnectToIntuit() Javascript function automatically starts the API authentication process where the connectToIntuit() requires a user to click the button.
    Note: We are simply using the Devise's user_signed_in? method but in a real-world implementation we would have to further distinguish whether the login originated at Intuit.
    • Since directConnectToIntuit() will not be launched in a popup we need to modify the app/views/vendors/close_and_redirect.html.erb view to handle this condition.
    • <script>
      setTimeout(function(){
          if(window.opener == null){
            window.location = '<%= @url %>';
          }else{
            window.opener.location = '<%= @url %>';
            window.close();
          }
      }, 10000);
      </script>
      
      Note: If window.opener is null then the Intuit API authentication request is not running in a popup (as seen in Part 1).
  5. Now we are ready to sign in using Intuit.
  6. Click on the "Sign in with Intuit" button.
    Next, you will be prompted for your QuickBook's credentials.
    You will then be briefly brought back to the Rails app, which then the directConnectToIntuit() code will kick in and take you to this page.
    Here is the close_and_redirect.html.erb modifications from step 3 in action.
    Lastly, we make it back again to the Rails app. Notice that the diconnect link is showing because we are authenticated against the Intuit API (1). Moreover, using Devise we are properly logged into the Billtastic Rails app (2) using our Intuit credentials.

The infamous "blue dot" menu

Stay tuned to Part 5 where I will implement the Intuit blue dot menu.