Ruby on Rails 4, Salesforce OAuth authentication and Restforce

Photo Credit: Bruno Fagundez

Ruby on Rails 4, Salesforce OAuth authentication and Restforce

Using rails 4 and Salesforce connected apps to perform OAuth authentication and interact with Salesforce data using the Salesforce REST API gem (restforce)

Edit I’ve updated some parts to work with the latest version of Rails at the moment (4.1.7). The code of this tutorial is here

The objective

In this post I’m going to explain how to add Salesforce OAuth authentication to a Rails application. Later I’ll be explaining how to use restforce gem to access Salesforce.com data on behalf of the authenticated user.

The Stack

Salesforce

Create a connected APP in salesforce

Head to Setup/Create/Apps:

At the bottom of the screen there’s a section called Connected apps click on New:

Fill the required fields with information about your app, and check “Enable OAuth Settings”:

After the app is created take note of the “Consumer Key” and “Consumer Secret”. The terminology is from OAuth 1.0 those now are called “Client Id” and “Client Secret”.

Ruby on Rails

Open your Gemfile and add the needed gems

  gem 'restforce'
  gem 'omniauth-salesforce'
  gem 'slim-rails'

The gem “slim-rails” is to use slim language for templating. I prefer it over erb because templates look lighter.

Install them running:

  $ bundle install

User model

Generate the user model.

  $ rails g model User provider uid name oauth_token refresh_token instance_url

Modify User model to interact with omniauth

We need to add this to the User model in order to update current user record when the log in is complete. Edit the file located at /app/models/user.rb :

  class User < ActiveRecord::Base
    def self.from_omniauth(auth)
      where(auth.slice(:provider, :uid).permit!).first_or_initialize.tap do |user|
        user.provider = auth.provider
        user.uid = auth.uid
        user.name = auth.info.name
        user.oauth_token = auth.credentials.token
        user.refresh_token = auth.credentials.refresh_token
        user.instance_url = auth.credentials.instance_url
        user.save!
      end
    end
  end

Add a helper method to interact with current_user

Edit /app/controllers/application_controller.rb, this helper will be available in your app so we can know current user data.

  class ApplicationController < ActionController::Base
    # Prevent CSRF attacks by raising an exception.
    # For APIs, you may want to use :null_session instead.
    protect_from_forgery with: :exception

    private
    def current_user
      @current_user ||= User.find(session[:user_id]) if session[:user_id]
    end
    helper_method :current_user
  end

Create a Sessions controller

Create a Sessions controller /app/controllers/sessions_controller.rb to manage user sessions.

  class SessionsController < ApplicationController
    def create
      user = User.from_omniauth(env["omniauth.auth"])
      session[:user_id] = user.id
      redirect_to root_url
    end

    def destroy
      session[:user_id] = nil
      redirect_to root_url
    end
  end

Add routes

Modify your /config/routes.rb adding this:

  match 'auth/:provider/callback', to: 'sessions#create', via: [:get, :post]
  match 'auth/failure', to: redirect('/'), via: [:get, :post]
  match 'signout', to: 'sessions#destroy', as: 'signout', via: [:get, :post]

Create a omniauth initializer

Create an initializer /config/initializers/omniauth.rb and add your connected app details.

  OmniAuth.config.logger = Rails.logger

  Rails.application.config.middleware.use OmniAuth::Builder do
    provider :salesforce, 'YOUR-CONSUMER-KEY', 'YOUR-CONSUMER-SECRET'
  end

Add a user widget to all pages

Remove your initial /app/views/layouts/application.html.erb and create an application.html.slim in the same directory with the following content:

  html
    head
      title My Salesforce/Rails connected app
      = stylesheet_link_tag    "application", media: "all", "data-turbolinks-track" => true
      = javascript_include_tag "application", "data-turbolinks-track" => true
      = csrf_meta_tags
    body
      div#current_user_status
        - if current_user
          p Welcome #{current_user.name}
        - else
          = link_to "Sign in with Salesforce", "/auth/salesforce", id: "sign_in"

      == yield

Restforce

With the OAuth infraestructure and the current_user helper in place, restforce initialization is quite easy:

 client = Restforce.new :oauth_token => current_user.oauth_token,
      :refresh_token => current_user.refresh_token,
      :instance_url  => current_user.instance_url,
      :client_id     => 'YOUR-CONSUMER-KEY',
      :client_secret => 'YOUR-CONSUMER-SECRET'

Tutorial Code

The code of this Tutorial can be found here. Salesforce Connected app “Consumer Key” and “Consumer Secret” must be set on config/application.rb . Additional interaction with Restforce can be seen on controllers/home_controller.rb.