DEV Community

Cover image for Integrating Google OAuth2 with Devise for a Ruby on Rails Application
Harsh patel
Harsh patel

Posted on

Integrating Google OAuth2 with Devise for a Ruby on Rails Application

As a Ruby on Rails developer, there often comes a time when you're required to implement authentication mechanisms in your application. Devise is one of the most popular authentication solutions within the Rails ecosystem. When combined with Google OAuth2, it enables an effortless sign-in experience for the users. In this article, I'm going to walk you through a step-by-step guide on how to set up Google OAuth2 with Devise on a Rails application, also incorporating exception handling to make your app robust and reliable.

Step 1: Setting up Google API

Our journey begins with creating a new project in the Google API Console. After creating the project, we'll need to enable the Google+ API (an essential part of the Google OAuth2 authentication process). Post this; you can create OAuth client ID credentials for your web application. Remember to add your callback URL as an Authorized redirect URI. For development, this usually takes the form http://localhost:3000/users/auth/google_oauth2/callback. Google provides a Client ID and Client Secret, which we will use later in the Rails application configuration.

Step 2: Configuring the Rails Application

The next step is to adapt your Rails application to the Google OAuth system. Start by adding the omniauth-google-oauth2 and dotenv-rails gems to your Gemfile. The latter helps to manage your environment variables effectively.

gem 'devise'
gem 'omniauth-google-oauth2'
gem 'dotenv-rails', groups: [:development, :test]
Enter fullscreen mode Exit fullscreen mode

After running bundle install to install these gems, create a .env file in the root of your Rails application. This is where we store the Google Client ID and Client Secret that we obtained earlier.

GOOGLE_CLIENT_ID=your_client_id
GOOGLE_CLIENT_SECRET=your_client_secret
Enter fullscreen mode Exit fullscreen mode

These environment variables are essential for your Rails application to communicate with the Google OAuth2 server. To integrate them, insert the following code into

config/initializers/devise.rb:

config.omniauth :google_oauth2, ENV['GOOGLE_CLIENT_ID'], ENV['GOOGLE_CLIENT_SECRET'], {}
Enter fullscreen mode Exit fullscreen mode

Next, we need to make sure our User model is omniauthable and can handle the callback data. To achieve this, update app/models/user.rb:

class User < ApplicationRecord
  devise :database_authenticatable, :registerable, :omniauthable, omniauth_providers: %i[google_oauth2]

  def self.from_omniauth(access_token)
    data = access_token.info
    user = User.where(email: data['email']).first

    # Uncomment the section below if you want users to be created if they don't exist
    unless user
        user = User.create(
           email: data['email'],
           password: Devise.friendly_token[0,20]
        )
    end
    user
  end
end
Enter fullscreen mode Exit fullscreen mode

Furthermore, we need to specify the callback in config/routes.rb:

devise_for :users, controllers: { omniauth_callbacks: 'users/omniauth_callbacks' }
Enter fullscreen mode Exit fullscreen mode

Finally, let's create the OmniauthCallbacksControllerin app/controllers/users/omniauth_callbacks_controller.rb, which will handle the authentication data returned by the Google OAuth2 server:

class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
  def google_oauth2
      @user = User.from_omniauth(request.env['omniauth.auth'])

      if @user.persisted?
        sign_in_and_redirect @user
      else
        session['devise.google_data'] = request.env['omniauth.auth'].except(:extra) # Removing extra as it can overflow some session stores
        redirect_to new_user_registration_url, alert: @user.errors.full_messages.join("\n")
      end
  end
end
Enter fullscreen mode Exit fullscreen mode

Step 3: Exception Handling

Last but not least, we must not overlook the importance of exception handling. Robust applications need to handle failures gracefully. For this purpose, we'll set up an OmniAuth exception handler.

In config/initializers/omniauth.rb:

OmniAuth.config.on_failure = proc do |env|
  "Users::OmniauthCallbacksController".constantize.action(:failure).call(env)
end
Enter fullscreen mode Exit fullscreen mode

And then add the failure method to OmniauthCallbacksController:

def failure
  flash[:error] = 'There was an error while trying to authenticate you...'
  redirect_to new_user_session_path
end
Enter fullscreen mode Exit fullscreen mode

Remember to restart your Rails server whenever you make changes to the initializers.

And voila! You've just set up your Rails application with Google OAuth2 using Devise, providing your users with an easy and secure way to sign in with their Google accounts. Happy coding!

Top comments (1)

Collapse
 
gmcamposano profile image
gmcamposano

When handling exceptions as you mentioned, there is a line in the docs that say:

NOTE: If you are using this gem with devise with above snippet in config/initializers/devise.rb then do not create config/initializers/omniauth.rb which will conflict with devise configurations.

What do you propose then to handle the exceptions as you code goes against the gems doc file?