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]
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
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'], {}
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
Furthermore, we need to specify the callback in config/routes.rb
:
devise_for :users, controllers: { omniauth_callbacks: 'users/omniauth_callbacks' }
Finally, let's create the OmniauthCallbacksController
in 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
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
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
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)
When handling exceptions as you mentioned, there is a line in the docs that say:
What do you propose then to handle the exceptions as you code goes against the gems doc file?