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 {

      info do
          email: raw_info['email'],

      extra do
        { raw_info: raw_info }

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

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>

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'

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

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.

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

Please Login to comment
3 Comment threads
0 Thread replies
Most reacted comment
Hottest comment thread
2 Comment authors
Serguei CambourChristopher Bartling Recent comment authors

This site uses Akismet to reduce spam. Learn how your comment data is processed.

newest oldest most voted
Christopher Bartling

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

Serguei Cambour

Good catch, Christopher, I had ti modify it as well. But it does not work event after that. I have the error: The redirect uri included is not valid when trying to access to localhost:3001. Here is the logs from server-side: Started POST "/oauth/authorize" for at 2018-01-11 13:11:36 +0100 Processing by Doorkeeper::AuthorizationsController#create as HTML Parameters: {"utf8"=>"āœ“", "authenticity_token"=>"RLn070X4yIbN+iFNzjC6TZTnXI+0zUK2w2cnhJYYBFHAjjvLwiACD/Yg0Kv+TymnOLt8/30MzU2RksM/5FdX7A==", "client_id"=>"b6f13bba6c963fe810b78c14e8eeb9975b8a24315a329ce494a25e3c8ed29d11", "redirect_uri"=>"http://localhost:3001/doorkeeper/callback", "state"=>"", "response_type"=>"code", "scope"=>"profile", "commit"=>"Authorize"} User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? ORDER BY "users"."id" ASC LIMIT ? [["id", 1], ["LIMIT", 1]] Doorkeeper::Application Load (0.1ms) SELECT "oauth_applications".* FROM "oauth_applications" WHERE "oauth_applications"."uid" = ? LIMIT ? [["uid", "b6f13bba6c963fe810b78c14e8eeb9975b8a24315a329ce494a25e3c8ed29d11"],… Read more »

Serguei Cambour

Sorry for the formatting, it seems like code button above does not work properly šŸ™