Access API using Omniauth

OmniAuth is a library that standardizes multi-provider authentication for web applications.

Context

When we use the connector framework to integrate with an external application, we need to have access to their API. All external API require authentication in order to access these external resources.

For most of them, authentication process is made via Oauth2. We will explain here a standard strategy for Oauth2 that can be used by the connectors in order to easily call external endpoints.

Beforehand, you may want to check if the external application already has developed some Gems that can directly handle access to their resources. A non-exhaustive list is available here: Omniauth strategies

Creating the strategy

First, add this line to your Gemfile:

gem 'omniauth-oauth2'

Then, create a file <application_name>.rb, located in lib/strategies.
The contents of the file below should be adapted yo your application:

# lib/strategies/myapp.rb
require 'omniauth-oauth2'

module OmniAuth
  module Strategies
    class SomeSite < OmniAuth::Strategies::OAuth2
      # Give your strategy a name.
      option :name, "some_site"

      # This is where you pass the options you would pass when
      # initializing your consumer from the OAuth gem.
      option :client_options, {site: "https://api.somesite.com"}

      # These are called after authentication has succeeded. If
      # possible, you should try to set the UID without making
      # additional calls (if the user id is returned with the token
      # or as a URI parameter). This may not be possible with all
      # providers.
      uid{ raw_info['id'] }

      info do
        {
          name: raw_info['name'],
          email: raw_info['email']
        }
      end

      extra do
        {
          'raw_info' => raw_info
        }
      end

      def raw_info
        @raw_info ||= access_token.get('/me').parsed
      end
    end
  end
end

Initialization

Add two environment variables in your application.yml:

# OAuth keys
application_client_id: <xxxx-xxx-xxx>
application_client_secret: <xxxxx>

Create the file config/initializers/omniauth.rb with the following code (to be adapted with what you wrote before):

require File.join(Rails.root, 'lib/strategies/<application_name>.rb')
Rails.application.config.middleware.use OmniAuth::Builder do
  provider :my_provider, ENV['application_client_id'], ENV['application_client_secret']
end

Usage

After having stored your user's first token and refresh_token during the authentication process (logic inside oauth_controller.rb), you can now use your strategy the following way:

DEFAULT_CLIENT_OPTIONS ||= {site: 'https://api.somesite.com', authorize_url: 'https://api.somesite.com/authorize', token_url: 'https://api.somesite.com/token'}

client = ::OAuth2::Client.new(ENV['application_client_id'], ENV['application_client_secret'], DEFAULT_CLIENT_OPTIONS)
token =  ::OAuth2::AccessToken.new(client, <my_oauth_token>, {refresh_token: <my_refresh_token>})

From there, if you want to call any external endpoint, you only need to do the following:

token.get(<my_get_url>)
token.post(<my_post_url>, body: <my_post_params>.to_json, headers: <my_custom_headers>)
...

 Later, whenever you encounter an HTTP 401 error, which would mean that your access token has expired, refreshing the token is as easy as:

token = token.refresh!

This will update the token, and the refresh_token, allowing you to perform your calls to the external API again.