Social Login in Ruby on Rails with Devise and Google

Social login/registration options can make for a smoother user experience, so they are almost always integrated into Mintbit applications. This article explains how to add a login option through Google and the security measures required to keep your private keys secure in the environment.

Use the dot-env gem for storing API keys in your .env file. Install dot-env by adding it to your Gemfile:

1
gem "dotenv-rails"

FIrst, run the command bundle install.

Add two files, .env and .env.sample in your project root and add .env in the .gitignore so your secret keys won’t be visible in git or anywhere else.

Now, let’s go ahead and add google login first.

Create a new application in google developers console, go to credentials, and press Create Credentials. Select OAuth client ID and then select Web application.

Configure it like this:

Screen Shot 2020-04-05 at 7.34.51 PM.png

Hit the create button at the bottom to get your API keys.

Screen Shot 2020-04-05 at 7.39.31 PM.png

Put these API keys in .env file like this:

1
2
GOOGLE_CLIENT_ID=xxxxxxx
GOOGLE_CLIENT_SECRET=xxxxxx

You will need to replace this with your actual keys.

Devise isn’t configured yet, so in order to use omniauth, first add Devise to your project.

Add devise gem to your Gemfile and run bundle install.

1
gem 'devise'

Run the following commands in your terminal:

1
2
rails generate devise:install
rails generate devise User

With that, you have successfully added Devise to your project. Now add omniauth. In your Gemfile add the following gem:

1
gem 'omniauth-google-oauth2'

Next, write a migration to add columns to the users table to keep record of Omniauth. In your terminal, run:

1
rails generate migration add_columns_to_users

In the migration file, add this:

1
2
3
4
5
6
class AddOmniauthToUsers < ActiveRecord::Migration[6.0]
  def change
    add_column :users, :provider, :string
    add_column :users, :uid, :string
  end
end

In your terminal:

1
rails db:migrate

Now add this line to devise.rb:

1
config.omniauth :google_oauth2, ENV['GOOGLE_CLIENT_ID'], ENV['GOOGLE_CLIENT_SECRET'], {}

Make user.rb something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class User < ApplicationRecord
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable,
         :omniauthable, omniauth_providers: %i[github google_oauth2]

  def self.from_omniauth(auth)
    user = User.find_by(email: auth.info.email)
    if user
      user.provider = auth.provider
      user.uid = auth.uid
      user.save
    else
      user = User.where(provider: auth.provider, uid: auth.uid).first_or_create do |user|
        user.email = auth.info.email
        user.password = Devise.friendly_token[0,20]
      end
    end
    user
  end
end

Add a new controller named omniauth_callbacks_controller.rb and paste the following method inside it:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class OmniauthCallbacksController < Devise::OmniauthCallbacksController
    def google_oauth2
      @user = User.from_omniauth(request.env['omniauth.auth'])
      if @user.persisted?
        flash[:notice] = I18n.t 'devise.omniauth_callbacks.success', kind: 'Google'
        sign_in_and_redirect @user, event: :authentication
      else
        session['devise.google_data'] = request.env['omniauth.auth'].except(:extra)
        redirect_to new_user_registration_url, alert: @user.errors.full_messages.join("\n")
      end
    end

    def failure
      redirect_to root_path
    end
 end

Now show a button in your views. Run this command in your terminal:

1
rails generate devise:views

In views/sessions/new.html.erb, put this:

1
<%= link_to "Sign in with Google", user_google_oauth2_omniauth_authorize_path %>

Lastly in routes.rb, put this:

1
devise_for :users, controllers: { omniauth_callbacks: 'users/omniauth_callbacks' }

Now you have configured OAuth with Google. Happy authenticating!