Oauth2 on Rails: the client application

In part 1 we completed the Oauth server application. We now need to build the client app:


rails new oauth-client

Then add the omniauth-oauth2 gem, which allows us to use Oauth2 by just creating a simple configuration (strategy) file:


gem 'omniauth-oauth2'

And now we need to to build the strategy.

The doorkeeper Omniauth strategy

Omniauth is a versatile gem, allowing programmers to use it with variety of oauth providers, each one with its own different configuration.

This is achieved by using strategies, there are plenty already built for you, but in order to authenticate to our oauth-server application we need to write a custom one. We are naming it “doorkeeper” after the name of the gem used in the server app that handles Oauth authentication.

Let’s create the file lib/doorkeeper.rb and put the following code in it:


require 'omniauth-oauth2'

module OmniAuth
  module Strategies
    class Doorkeeper < OmniAuth::Strategies::OAuth2
      option :name, 'doorkeeper'
      option :client_options, {
        site:          'http://localhost:3000',
        authorize_url: 'http://localhost:3000/oauth/authorize'
      }

      uid {
        raw_info['id']
      }

      info do
        {
          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

Here we define a class, we give the strategy the name “doorkeeper”, we specify some urls where omniauth will go to manage the server authentication. The #raw_info method instead is used to fetch the information about the user logged on the server application (again, in the previous post we wrote the code, it’s inside application_controller.rb). The bulk of this class is just omniauth boilerplate, to see an example and some more details on building strategies you can visit the gem readme.

Now we need to generate the omniauth initializer:


touch config/initializers/omniauth.rb

and put this code in it:


require 'doorkeeper'

Rails.application.config.middleware.use OmniAuth::Builder do
  provider :doorkeeper, <application_id>, <application_secret>
end

We require the strategy we just defined, then we tell omniauth to add it to its current strategies (and eventually to the application middlewares).
Of course we must replace <application_id> and <application_secret> with the values we got when creating the client application configuration on the server (when in the previous post we visited http://localhost:3000/oauth/applications/new … remember?)

The omniauth configuration is not over yet: we need to add some omniauth routes in config/routes.rb:


Rails.application.routes.draw do
  root to: redirect('/auth/doorkeeper')

  get '/auth/:provider/callback' => 'application#authentication_callback'
end

The first line redirects to the path ’/auth/doorkeeper’, which will be handled by omniauth. The second is the callback url, used when returning from the server authentication process. Let’s write the code for its action, directly in application_controller.rb:


class ApplicationController < ActionController::Base
  auth = request.env['omniauth.auth']
  render json: auth.to_json
end

OmniAuth will always return a hash of information after authenticating with an external provider in the Rack environment under the key omniauth.auth. We access that object and render it as json.

Try it

It’s time to start both applications: oauth-server must run on port 3000, while oauth-client must run on 3001. When you visit localhost:3001 this is what should happen:

  • you are redirected to /auth/doorkeeper, a url that will start the Oauth authentication using the “doorkeeper” omniauth strategy
  • You are furher redirected to the server-app
  • If you aren’t authenticated on the server-app you will be redirected to localhost:3000/users/sign_in.
  • After successful sign in on the server, you will be redirected on the client app at /auth/doorkeeper/callback. Here you will see the information we got from the server app in json format.
image

At this point you can save the user information received from the server app in the client app database and build your user data and resources from there.

Leave a Reply

Sort by:   newest | oldest | most voted
Christopher Bartling
Member

Great article series and they really helped me with integrating OAuth2 authentication into our application suite. There is one issue in the above article around the ApplicationController–the authentication_callback method is not defined. It should be the following:

class ApplicationController < ActionController::Base
def authentication_callback
auth = request.env['omniauth.auth']
render json: auth.to_json
end
end

wpDiscuz