Google Authentication in Ruby On Rails

This article will show you how to allow your users to authenticate using Google. (UPDATED!)


Published on:June 9, 2016

This article shows you how to enable Google authentication for your Ruby on Rails application.

As mentioned in our Facebook Authentication in Ruby on Rails Guide, many developers find it convenient to utilize third party authentication services such as Facebook or Google instead of using their own login system. Using these services can be more sure and they also provide a better overall user experience.

Google App Setup

Heads Up!Updated June 8th, 2016 for Rails 4.2 and 5.0. This update also fixes the forbidden attributes error.

Before we can work on the actual code for authentication, we need to do some setup on the Google side of things.

First, sign into the Google APIs console at https://console.developers.google.com . Then click on the 'Select a project' dropdown in the upper right and click Create Project.

Create Project screenshot

The create project modal will appear. Enter a project name and agree to the terms of service, then click 'Create'.

Create Project modal screenshot

Next, do a search for contacts then click on the Contacts API entry that pops up.

search for api screenshot

Click the blue enable button, then click the back button right next to it once it enables.

contacts api details screenshot

Now do another search for google+ and click the Google+ API entry that appears.

search for google plus screenshot

Click the enable button.

google plus api details screenshot

Now click the Credentials link on the left side of the screen.

credentials screenshot

Next, click Oauth Consent Screen, fill in the details, and click save.

oauth consent screenshot

Next click the blue button that says Create Credentials and choose OAuth client ID. create credentials screenshot

Choose Web application, enter http://localhost:3000/auth/google_oauth2/callback, then hit create. create web application screenshot

A box will pop up containing your credentials, copy them to a text file, you will need them later.

credential details screenshot

Now we are ready to build our Rails application!

Building the Rails Application

Now that we've set up things with Google, we need to add the code necessary to do the actual authentication. The best way to authenticate with Google is to use the omniauth-google_oauth2 gem. This gem allows you to quickly and easily add Google authentication, and it plays nice with all of the other omniauth gems. Add the gem to your gemfile.

Gemfile:

gem "omniauth-google-oauth2", "~> 0.2.1"

Now run a bundle install.

Next, we need to create an initializer. Create an initializer in the initializers folder called omniauth.rb and add the code listed below. If you are editing an existing project that already uses omniauth you can just add the code below to your existing omniauth.rb file. Make sure to replace my Google client id with your Google client id, and my Google client secret with your Google client secret.

config/initializers/omniauth.rb:

OmniAuth.config.logger = Rails.logger

Rails.application.config.middleware.use OmniAuth::Builder do
  provider :google_oauth2, 'my Google client id', 'my Google client secret', {client_options: {ssl: {ca_file: Rails.root.join("cacert.pem").to_s}}}
end

On some systems, Rails is unable to find any cert files for SSL certificates. This presents a problem since the actual authentication is done via SSL. To resolve this, you will need to download this cert file and place it in the root directory of your Rails application making sure the file does not have a .txt extensionn on the end. You can also attempt to locate the directory on your own system and change the path listed in the omniauth initializer, but that is beyond the scope of this article.

Next, lets create a user model to store our user information. Run the commands below to create this now.

Terminal Commands:

rails g model user provider uid name oauth_token oauth_expires_at:datetime
rake db:migrate

Now we need to create two controllers. The first controller, Home, is simply the landing page. The second controller, Sessions, will actually contain the logic that lets our users log in and out. Run the commands below to create these controllers.

Terminal Commands:

rails g controller home show
rails g controller Sessions create destroy

Great! Now we need to set up a few routes. Modify your routes file so that it looks like the code listed below.

config/routes.rb:

GoogleAuthExample::Application.routes.draw do
  get 'auth/:provider/callback', to: 'sessions#create'
  get 'auth/failure', to: redirect('/')
  get 'signout', to: 'sessions#destroy', as: 'signout'

  resources :sessions, only: [:create, :destroy]
  resource :home, only: [:show]

  root to: "home#show"
end

The auth/:provider/callback route actually handles the callback from Google back to omniauth. The auth/failure route is used when an error occurs. The signout route is used when the user clicks the log out button on your website. The rest of the routes just set up the controllers in your application and adds a site root.

The next thing we need to do is add some code to our User model. Open your users model and modify it so that it looks like the code listed below.

app/models/user.rb:

class User < ActiveRecord::Base
  def self.from_omniauth(auth)
    where(provider: auth.provider, uid: auth.uid).first_or_initialize.tap do |user|
      user.provider = auth.provider
      user.uid = auth.uid
      user.name = auth.info.name
      user.oauth_token = auth.credentials.token
      user.oauth_expires_at = Time.at(auth.credentials.expires_at)
      user.save!
    end
  end
end

This code will take the data that Google returns and persist it to the database. If the user does not exist, a new one will be created, otherwise, the existing user will be updated.

Next, we will need to add some code to our application controller that will allow us to determine if the user is logged in or not. Open your application controller and modify it so that it looks like the code listed below.

app/controllers/application_controller.rb:

class ApplicationController < ActionController::Base
  protect_from_forgery with: :exception
  helper_method :current_user

  def current_user
    @current_user ||= User.find(session[:user_id]) if session[:user_id]
  end
end

The current_user function will check to see if the user_id exists in the session. If so it will return the current user. The helper method tells rails we wish to use this in our helpers and views as well.

Now, lets add some code to our sessions controller. This code tells rails how to return the callback that omniauth does. Open your Sessions controller and modify it so that it looks like the code listed below.

app/controllers/sessions_controller.rb:

class SessionsController < ApplicationController
  def create
    user = User.from_omniauth(env["omniauth.auth"])
    session[:user_id] = user.id
    redirect_to root_path
  end

  def destroy
    session[:user_id] = nil
    redirect_to root_path
  end
end

Next, lets modify our application layout and add a sign in/sign out link. Open your application layout and modify it so that it looks like the code listed below.

app/views/layouts/application.html.erb:

<!DOCTYPE html>
<html>
  <head>
    <title>Google Auth Example App</title>
    <%= stylesheet_link_tag    "application", media: "all", "data-turbolinks-track" => true %>
    <%= javascript_include_tag "application", "data-turbolinks-track" => true %>
    <%= csrf_meta_tags %>
  </head>
  <body>
    <div>
      <% if current_user %>
        Signed in as <strong><%= current_user.name %></strong>!
        <%= link_to "Sign out", signout_path, id: "sign_out" %>
      <% else %>
        <%= link_to "Sign in with Google", "/auth/google_oauth2", id: "sign_in" %>
      <% end %>
    </div>
    <div>
    <%= yield %>
    </div>
  </body>
</html>

Now, if we start a rails development server and visit http://localhost:3000 we can try it out. Click the sign in link and you will be taking to a prompt that will ask you to sign in. Note that what you see below might vary slightly if you are already signed into your Google account.

Google sign in screenshot

Once you have signed in you will be prompted to allow the application to access your email address and basic information. Click accept and you will be signed into your app via Google.

API Access screenshot

That's it! You've successfully added Google Authentication for your app! Thanks for reading!