How to Add Google One Touch Authentication to a Ruby on Rails Application

Typing Passwords is So 2013

Patrick Karsh
5 min readApr 28, 2023
You have probably seen this on a ton of sites

Passwords are annoying

Typing in passwords can often be a tedious and frustrating experience. It requires a great deal of attention to ensure that the correct characters are being entered, and mistakes can be costly, leading to account lockouts or security breaches. Additionally, many websites and applications require complex password criteria, such as a minimum length or the inclusion of special characters, making it difficult to remember the password. Furthermore, having to type in passwords repeatedly can be time-consuming and interrupts workflow. Despite the importance of password security, the act of typing in passwords can still be seen as an annoying aspect of modern life.

But what if there was another way? Google’s authentication system is widely used and trusted by millions of users worldwide. However, traditional authentication mechanisms such as passwords, SMS codes, or hardware tokens can be cumbersome and not always secure enough. One alternative is Google’s One Touch, which provides a seamless authentication experience using a user’s existing Google session. In this article, we’ll explore how to use the ‘googleauth’ gem to implement One Touch authentication in Ruby applications.

Setting up One Touch Authentication is easy and straightforward, requiring minimal coding and technical expertise. Developers can use pre-built libraries and SDKs for various platforms to quickly add robust authentication features to their applications.

Here is a basic six-step process to set up an implementation of it.

This is written assuming you have an existing User model and Devise installed

Obtain Your Application’s Client ID from Google

You will need a Google API client ID in order to use Google One Tap. Follow the instructions from the Sign In With Google Setup guide here.

Be sure to set http://localhost and http://location:3000 in your “Authorized JavaScript Origins” in order to run this locally along with the domain(s) of your production app.

Note that your application domain must be using SSL for this to work in production.

Your client ID should look something like this:

`56048765987236578.apps.googleusercontent.com` 

Store your client ID in either an environment variable or in your Rails credentials. For this post, we’ll use an environment variable:

 ENV[“GOOGLE_CLIENT_ID”]

Install the Googleauth Gem

# Gemfile
gem 'googleauth'

The Googleauth gem is a Ruby library that provides a simple way to authenticate to Google APIs using OAuth2. It handles the creation of OAuth2 client IDs, generating access tokens, and refreshing access tokens when they expire. The gem is commonly used in Ruby on Rails applications that interact with Google services such as Google Drive, Google Sheets, and Google Calendar. Once included in the Gemfile, the Googleauth gem can be installed by running the “bundle install” command in the terminal.

Create a Controller to Handle the OAuth Callback from Google

# frozen_string_literal: true
# app/controllers/callbacks_controller.rb
class CallbacksController < ApplicationController
def google_onetap
if g_csrf_token_valid?
payload = Google::Auth::IDTokens.verify_oidc(params[:credential], aud: ENV['GOOGLE_CLIENT_ID'])
user = User.from_google_payload(payload)
sign_in(user) # this sign_in comes from devise, yours may differ
redirect_to(root_path)
else
redirect_to(user_session_path, notice: 'sign in failed')
end
end

private

def g_csrf_token_valid?
cookies['g_csrf_token'] == params['g_csrf_token']
end
end

This code defines a CallbacksController class in a Rails application that inherits from ApplicationController. The controller has a single action google_onetap, which handles the callback from Google's One Tap authentication. When a user logs in using their Google credentials, the google_onetap action first checks if the Google-provided CSRF token is valid by comparing the token stored in cookies with the one received in the request parameters. If the tokens match, the action proceeds to verify the ID token (JWT) using the Google::Auth::IDTokens library, with the Google OAuth client ID as the audience. Upon successful validation, it retrieves or creates a user record based on the Google user data and signs them into the application, redirecting them to the root path. If the tokens do not match or the ID token cannot be verified, the user is redirected to the user session path with a notice that the Google sign-in has failed.

Adding a Route to Your Controller

# routes.rb 
post '/google_onetap_callback', to: 'callbacks#google_onetap', as: :google_onetap_callback

This code defines a POST route in the Ruby on Rails application’s “routes.rb” file that maps the URL “/google_onetap_callback” to the “google_onetap” method in the “callbacks” controller.

Updating the User Model

class User < ApplicationRecord
validates :email, presence: true, uniqueness: true
validates :password, presence: true
end

This is written assuming you have an existing User model and Devise installed that may look something like this.

class User < ApplicationRecord
validates :email, presence: true, uniqueness: true
validates :password, presence: true

def self.from_google_payload(payload)
where(email: payload['email']).first_or_create { |user|
user.email = payload['email']
user.password = Devise.friendly_token[0, 20] if user.password.blank?
}
end
end

from_google_payload(payload) is a class method that takes in a payload parameter and creates a new user record in the database based on the information from the payload. It first searches for an existing user with the email address provided in the payload. If a user with that email address already exists, it returns that user. If no user with that email address exists, it creates a new user and sets the email address to the one provided in the payload. It also generates a random password for the user using the Devise gem’s friendly_token method if the user does not already have a password set. This method is commonly used for authenticating users via Google OAuth.

The payload you are ingesting into from_google_payload(payload) will look something like this:

{
"iss" => "https://accounts.google.com",
"email" => "patrick.k@kash.co",
"email_verified" => true,
"name" => "Patrick Karsh",
"picture" => "https://lh3.googleusercontent.com/a/AGN",
"given_name" => "Patrick",
"family_name" => "Karsh"
}

Add The Modal to the View

#app/views/layouts/application.html.erb
<script src="https://accounts.google.com/gsi/client" async defer></script>
<div id="g_id_onload"
data-client_id="<%= ENV['GOOGLE_CLIENT_ID']%>"
data-login_uri="<%= google_onetap_callback_url %>"
data-authenticity_token="<%= form_authenticity_token %>"
data-itp_support="true"
>
</div>

This is a section of an HTML file that includes a script tag to load the Google One Tap API client library asynchronously. This script is used to enable users to sign in to the application using their Google account with just one tap, without having to enter their credentials again. The div tag with the g_id_onload ID specifies the configuration parameters for the Google One Tap API. The “data-client_id” attribute sets the client ID of the Google Cloud Console project associated with the application. The data-login_uri attribute specifies the URL for the Google One Tap callback action in the application. The data-authenticity_token attribute specifies the CSRF token required for security purposes. The data-itp_support attribute enables Intelligent Tracking Prevention (ITP) support for Safari browsers.

Presto

You may need to restart your server to see it, but you would see the one touch modal popup now.

--

--

Patrick Karsh

NYC-based Ruby on Rails and Javascript Engineer leveraging AI to explore Engineering. https://linktr.ee/patrickkarsh