Here's my recipe to quickly set up Google OAuth login without using the devise gem, only pure Omniauth.
Install dependencies
Add these to your Gemfile:
gem 'omniauth'
gem 'omniauth-google-oauth2'
gem 'omniauth-rails_csrf_protection', '~> 0.1'
then `bundle install`.
# Create the user table and model
The absolute minimum is email, provider, and UID, but I usually go with:
```ruby
rails g migration create_users first_name last_name email image provider uid
Run the migration:
rails db:migrate
Then create a new User model:
# app/models/user.rb
class User < ApplicationRecord
def name
[first_name, last_name].join(' ')
end
def update_dynamic_attributes(auth)
self.first_name = auth.info.first_name
self.last_name = auth.info.last_name
self.email = auth.info.email
self.image = auth.info.image if auth.info.image?
end
class << self
def find_or_create_with_omniauth(auth)
user = find_by(auth.slice(:provider, :uid)) || initialize_from_omniauth(auth)
user.update_dynamic_attributes(auth)
user.save!
user
end
def initialize_from_omniauth(auth)
new do |user|
user.provider = auth.provider
user.uid = auth.uid
end
end
end
end
Setup Omniauth
We'll add a required callback route, but also two custom routes just for the comfort of using `sign_in_path` and `sign_out_path`:
# config/routes.rb
Rails.application.routes.draw do
# AUTHENTICATION ROUTES
get 'auth/:provider/callback', to: 'sessions#create'
get '/sign_out', to: 'sessions#destroy', as: :sign_out
get '/auth/google_oauth2', as: :sign_in
get '/auth/failure' => 'sessions#failure'
end
Create a config/omniauth.rb
file like the below:
# config/omniauth.rb
Rails.application.config.middleware.use OmniAuth::Builder do
provider :google_oauth2, ENV.fetch('GOOGLE_CLIENT_ID'), ENV.fetch('GOOGLE_CLIENT_SECRET')
end
OmniAuth.config.allowed_request_methods = %i[get]
OmniAuth.config.silence_get_warning = true
Handle sign-in, sign-out, and eventual failures
class SessionsController < ApplicationController
def create
user = User.find_or_create_with_omniauth(request.env['omniauth.auth'])
session[:user_id] = user.id
redirect_to after_sign_in_path, notice: "Signed in as #{user.name}"
end
def failure
Sentry.capture_message(params[:message])
redirect_to root_url, alert: 'Authentication failed.'
end
def destroy
session[:user_id] = nil
redirect_to root_url, notice: 'Signed out'
end
private
def after_sign_in_path
request.env['omniauth.params']['after_sign_in_path'] || request.env['omniauth.origin'] || user_projects_path
end
end
For more details about the failure handling part, I wrote a specific article to document it here: https://www.mdless.com/articles/9-how-to-handle-failures-with-omniauth-rails
Add a current_user helper method
To use a similar method as devise, let's create a custom current_user
helper:
class ApplicationController < ActionController::Base
helper_method :current_user
private
def current_user
@current_user ||= User.find_by(id: session[:user_id]) if session[:user_id]
end
end
Add links to sign in and sign out
In our views, we'll add links allowing users to connect:
<% if current_user %>
signed in as <%= current_user.name %>
<%= link_to 'sign out', sign_out_path %>
<% else %>
<%= link_to 'sign in with google', sign_in_path %>
<% end %>
ย