Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

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.

Info

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:

Code Block
languageruby
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:

Code Block
languageruby
# 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:

Code Block
languageruby
# 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):

Code Block
languageruby
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:

Code Block
languageruby
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:

Code Block
languageruby
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:

Code Block
languageruby
token = token.refresh!

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