A simple way to set Devise with Omniauth2.0 (Facebook, Google)

Sergio Cortes Satizabal
10 min readApr 15, 2021

--

Hello, my fellow excited and tired programmers.

Like many of you, if not all, we face constant problems and errors in our works that many times become simply overwhelming. Especially on those occasions where you see yourself wasting 2 or 3 precious hours on something that neither gives you knowledge nor develops your work further. I just those nasty bugs that take our chunks of free time away.

However, this is what we do. This is why we dig ourselves into vast lines of variables, constant, and numbers and try to form a mental map of its puzzle. We thrive to fix errors and we feed on those fixings accomplishments like a nice cold beer on a summer day. This is what we love to do, nonetheless is always good to skip the simple time-consuming steps that will take your valuable time.

Being coders means we must seek solutions and come up with ingenious ways to bypass problems. However, our job is so extensive that we all need a helping hand, and as such, I hope this article may help your day and ease your mind.

Without further due, let’s start.

When setting up a rails application that uses the devise gem, we automatically get access to an important and useful tool to make the user’s experience even better.

Omniauth2.0 can be included within the devise setup in rails allowing us to include Facebook, Google, Github, Twitter, and Digital Ocean sign_up options through secure verification.

In this tutorial, we will do a brief but explanatory session on how to set up Omniauth2.0 on your rails-devise application and the necessary steps to set it up.

For purposes of this article, this guide will only include Facebook and Google authentication methods. Nonetheless, the code will be open to adding other providers as needed with little further set_up

1. Make sure you have devise set_up in your application

For this guide purpose. you must have a rails app set up using devise authentication. If not, please follow this Hackernoon guide

2. Set up Omniauth2.0 Gemfile

Make sure you update your current gem “devise” for this and add the following gems:

gem 'devise', github: 'heartcombo/devise', branch: 'ca-omniauth-2'gem ‘omniauth’gem ‘omniauth-facebook’gem ‘omniauth-google-oauth2’gem ‘omniauth-rails_csrf_protection’
Gemfile

After saving the file make sure to run the console within the root folder:

bundle install

3. Setting up the proper columns for our devise model.

The next step will be to add the proper columns to our devise model (For this guide purposes, our devise model is called User)

rails g migration AddOmniauthToUsers provider:string uid:string

The above command will include into the User(devise) model the proper necessary columns to properly set Omniauth. This is how our migration file will look

Now please run the command:

rake db:migrate

4. Setting up Omniauth credentials call in devise initializer.

Inside the folder config/initializers/devise.rb, add the following block of code at the end of the block:

config.omniauth :facebook, ENV["APP_ID"], ENV["APP_SECRET"], access_type: "online"config.omniauth :google_oauth2, ENV["GOOGLE_CLIENT_ID"], ENV["GOOGLE_CLIENT_SECRET"], access_type: "online"

At this point, you may add an extra config.omniauth line including another provider. You can add your custom names to:

config.omniauth :[provider], ENV[“custom secret id”], ENV[“custom app id”], access_type: "online"

Later on, in the guide, we will set up the proper tokens for this. As they must be secretly saved in an .env within the root of our project. (There is as well a way to set them us as credentials which we will explain at the end)

5. Setting up the correspondent devise associations to the User (devise) model.

  • Direct yourself to the folder model/user.rb (or the name of your devise model)

When we set up device, we get a preset devise association within our User model. This association can extend its capabilities to allow for extra functionality such as mail confirmation (confirmable attribute).

In this case, we must extend the capabilities of our devise to include the omniauthable extension. As well we must indicate which providers we will use. For this guide purposes, we are setting up Facebook and Google authentication systems.

Make sure to add this at the end of your devise setup.

:omniauthable, omniauth_providers: %i[google_oauth2]

In my case it looks like this:

At this step, you may add another custom provider such as github, twitter, or digitalocean.

6. Adding the model creation method to include the omniauth info in our database

Within the same user model, we can define a method that takes care of all our general needs of basic information such as email and password.

Note: if you have any custom name added to your User (devise) model, you must specify this as well within the user model method to properly add its parameters.

To get all the callable API parameters, please direct yourself to the google_oauth2 or omniauth_facebook documentation for further Hash calls.

Add the following code to your model/users.rb

def self.from_omniauth(auth)# This line checks if the user email received by the Omniauth is already included in our databases.  user = User.where(email: auth.info.email).first# This line sets the user unless there is a user found in the line above, therefore we use ||= notation to evaluate if the user is nill, then set it to the User.create
.
user ||= User.create!(provider: auth.provider, uid: auth.uid, email: auth.info.email, password: Devise.friendly_token[0, 20])
user
end

You may add your custom column to your devise models such as name or last name. The following example shows a method that adds the name to the model

  • Method that doesn’t include a Name column:

7. Let’s add our Callbacks methods to our Omniauth architecture.

Adding callbacks to our Omniauths methods is necessary to properly direct the procces while the Authentication takes place within a third-party provider such as Facebook or Google. therefore is necessary to handle this procces to correctly return to our page or handle errors.

For this guide purposes, we have added our callbacks method within a created file “users” inside controllers

app/controllers/users/omniauth_callbacks_controller.rb

Note: Make sure to name the file: omniauth_callbacks_controller.rb

You may create this file within the main controller folder. Just make sure to change the correspondent route while passing the omniauth_callbacks folder route.

Paste the following code inside this file:

class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksControllerdef facebook
@user = User.from_omniauth(request.env['omniauth.auth'])
if @user.persisted?
sign_in_and_redirect @user, event: :authentication
set_flash_message(:notice, :success, kind: 'Facebook') if is_navigational_format?else session['devise.facebook_data'] = request.env['omniauth.auth'].except(:extra) redirect_to new_user_registration_urlendenddef failure
redirect_to root_path
end
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
elsesession['devise.google_data'] = request.env['omniauth.auth'].except('extra') redirect_to new_user_registration_url, alert: @user.errors.full_messages.join("\n")endendend

It should look like this

At this step, you may add additional methods to handle extra Omniauth providers such as twitter, github, or digitalocean following the previous architecture and replacing [omni_provider] and [provider] with correspondent authenticator

def [omni_prvider]# You need to implement the method below in your model (e.g. app/models/user.rb)@user = User.from_omniauth(request.env[‘omniauth.auth’])if @user.persisted?flash[:notice] = I18n.t ‘devise.omniauth_callbacks.success’, kind: ‘[provider]’sign_in_and_redirect @user, event: :authenticationelsesession[‘devise.[provider]_data’] = request.env[‘omniauth.auth’].except(‘extra’) # Removing extra as it can overflowredirect_to new_user_registration_url, alert: @user.errors.full_messages.join(“\n”)endend

8. Let’s add the corresponding device Omniauth routes

Up to this point, all steps we have done, ensure a more dynamic way to load Omniauthenticaros using the device setup and taking advantage of its methods and views.

By default, devise will set the following to our config/routes.rb file
devise_for :users

devise_for :users

Nonetheless, we must include the routes created by our callbacks class method. If you remember, in our last step we set up our callback to handle the page’s authentication procces. Such callback will help the routes to create the corresponding URL call using our callbacks methods names (facebook, google_oauth2)

Please replace that line with the following:

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

This line will create the corresponding routes paths to access our google and facebook authentication procces as shown below:

9. Adding the sign_up links to our views

This step might be done in 2 ways.

9.1 Create a direct link in any view you need it to using this code:

#Facebook
<%= link_to "Register with 'provider'", user_facebook_omniauth_authorize_path, method: :post %>
#Google
<%= link_to "Register with 'provider'", user_google_oauth2_omniauth_authorize_path, method: :post %>

We have added the method: :path to the link as is neccesary for it to properly set the method for its correposnidng route.

9.2 Dynamic View

As devise includes its own dynamic embeded method to render different links such as log in, sign in, forgot password. This same procces applies to our omniauth links, which we can set dinamically by modifying our views/device/shared/_links.html.erb

Modify the last line (21 -25) of the file _links.html.erb as follows

<%- if devise_mapping.omniauthable? %><%- resource_class.omniauth_providers.each do |provider| %># This line is included to set our google provider name to "Google" as by default the name is "gogogle_omniauth2", for the remaining providers the name is the same.<% pretty_provider = provider.to_s == 'google_oauth2' ? "Google": provider %><%= link_to "Sign in with #{OmniAuth::Utils.camelize(pretty_provider)}", omniauth_authorize_path(resource_name, provider), method: :post%><br /><% end %><% end %>

Note: Please note we have included method: :post as well. As is needed to properly recognize accept the route.

10. Set up your facebook credential and google credentials.

Faceboook

  • Click More options
  • Click on “something else”
  • Add your custom App name
  • Complete the security check (please make sure to turn off ad blockers otherwise the security check will not popup).
  • Once in your application dashboard, click on Setting
  • Choose the option basics
  • Within the field “app domains” write localhost.
  • Scroll down to Add a platform and click on it. Then choose (‘website’)
  • Set its URL to [https://localhost]
  • Save changes and save your (app_id and app_secret) for later.

Google

  • Direct yourself to API overviews
  • Select credentials
  • In the bottom right part, select “create credential”
  • Select OAuth client ID
  • Select configure consent screen
  • Select external or internal depending on your options
  • Give it the app name, email, and developer consent email at the bottom of the page.
  • Save and continue the remaining steps, no changes needed.
  • Once you are in the main dashboard, go to Credentials
  • Click again on Create Credential.
  • This time it will ask for you to set the type. Select “Desktop app”
  • Find your Client ID and Client secret within the credentials created.

11. Adding the credential to your project.

Adding this credential to your project is quite straightforward. nonetheless, bear to mind that this is not the only way to include credentials.

  • Create a file called .env within the main root of your application (where Gemfile resides)
  • Inside this new file, place the following
HTTPS = true#GOOGLE
GOOGLE_CLIENT_ID="Client ID"
GOOGLE_CLIENT_SECRET="Client secret"
#FACEBOOK
APP_ID="App id"
APP_SECRET="App secret"

Remember that we set at the beginning, within our config/initializers/device.rb two lines of code that will grab these secret tokens and use them to properly authenticate and connect to facebooks API.

12. [OPTIONAL] Facebook using credentials instead of .env tokens.

It might be that Facebook does not accept your tokens residing within the .env file. If such a thing happens and you get a page with unauthorized text or any other error regarding facebook app credentials. You might need to set it up as follows

Make sure you change the file residing in config/initializers/device.rb and replace the config.omniauth :facebook with the following line

config.omniauth :facebook, Rails.application.credentials.facebook[:APP_ID], Rails.application.credentials.facebook[:APP_SECRET], token_params: { parse: :json }

This way, our credential will read from our encoded credential file living in config/credentials.yml.enc

To modify this file, you must do the following in your command line inside the root path of your folder

EDITOR="code --wait" bin/rails credentials:edit

Note: replace “code”(visual studio code) for your editor of preference

  • Inside the opened file, please add and save the following
facebook:
APP_ID: <facebook_app_id>
APP_SECRET: <facebook_app_secret>

That’s all my friends. At this point, you should be able to use Facebook and Google sign_up systems. However, bear to remember that Facebook or Google will allow this feature in a localhost environment. For deployment and deployed apps, you may need to follow and comply with this companies requirements to set your app live.

Please feel free to comment, suggest or highlight something you think is wrong or think may need to be added

Thank you

--

--

Sergio Cortes Satizabal

Passionate about life and technology… True believer of the changes we can generate by our attitude and dedication.