Setting up User Authentication in Rails (Devise, Facebook,Twitter,Google)

I this Tutorial we will create a new rails application in which we will setup social authentication.

We are starting with implementation of user authentication in rails with Devise later followed by implementing social authentication options for users using omniauth.

Basic Application Setup:

rails new social_auth_demo

## Gemfile

## gems for authentication
gem 'devise'
gem 'devise-async'
gem 'omniauth-facebook'
gem 'omniauth-google-oauth2'
gem 'omniauth-oauth2', '~> 1.3.1'
gem 'omniauth-twitter'
gem 'twitter'
gem 'google-api-client', '0.8.2', require: 'google/api_client'

Now we need to run the devise generators.
we will also copy the devise views as we will be doing further modifications on few of the pages.

rails generate devise:install

copies over config/initializers/devise.rb and a localized message file.
Follow the outputed instuctions to setup flashes and mailer configs.

rails generate devise User
rails generate devise:views

Lets create a basic controller to see if our login works

rails g controller welcome index
rake db:create
rake db:migrate


get 'welcome/index'
root 'welcome#index'

WeclomeController should now look like

## app/controllers/welcome_controller.rb

class WelcomeController
  before_action :authenticate_user!

  def index

## app/views/welcome/index.html.erb
<%= link_to “Signout”, destroy_user_session_path, method: :delete %>

The method: :delete part is something we usually forget about.
Now test the application for normal devise authentication

Configure Omniauth


config.omniauth :google_oauth2, 'APP_ID', 'APP_SECRET', scope: 'user,public_repo'
config.omniauth :facebook, 'APP_ID', 'APP_SECRET', scope: 'user,public_repo'
config.omniauth :twitter, 'APP_ID', 'APP_SECRET', scope: 'user,public_repo'

replace 'APP_ID' withyour app id
replace 'APP_SECRET' withyour application secret key
set scopes as per application requirement

We pass in scopes to a few strategies, which is where we can configure omniauth to request specific permissions.
Sometimes you need to enable them on the remote side before you can request things (e.g. google, twitter) so make sure that things are setup there.

Tell Devise about omniauthable


devise :database_authenticatable, :registerable,:confirmable,
:recoverable, :rememberable, :trackable, :omniauthable,:validatable,
:omniauth_providers => [:facebook,:google_oauth2,:twitter]

Create Identity model to store access_keys and metadata

Now we are ready to plug in oauth authentications. The flow is:
1. User requests /users/auth/:provider, where provider one of the strategies that you defined above.
2. Omniauth does magic and directs the user to the remote service.
3. The user grants us access and is redirected to the callback path.
4. The OmniauthCallbacks controller is called on our application with the relavent info.
We will use this info to create the user. We are also going to store it to be able to access the service on behalf of the user, and we’ll need to store the access_token in order to do so.
Google is slightly more complicated and we’ll need to store a refresh_token as well.

rails g model identity user:references provider:string accesstoken:string refreshtoken:string uid:string name:string email:string nickname:string image:string phone:string urls:string
rake db:migrate


class Identity < ActiveRecord::Base
  belongs_to :user
  validates_presence_of :uid, :provider
  validates_uniqueness_of :uid, :scope => :provider

  def self.find_for_oauth(auth)
    identity = find_by(provider: auth.provider, uid: auth.uid)
    identity = create(uid: auth.uid, provider: auth.provider) if identity.nil?
    identity.accesstoken = auth.credentials.token
    identity.refreshtoken = auth.credentials.refresh_token = =
    identity.nickname =
    identity.image = =
    identity.urls = ( || "").to_json

Create OmniauthCallbacksController to pull in data

We’re going to build one method to handle the different authentication callbacks, called generic_callback.
The logic of this controller is:
1. Find or create an Identity object for the incoming oauth data. Update it with the latest info.
2. If there is no user associated with the Identity, associate it with the current_user.
3. If there is no current_user, create a new User object.
4. If the User object doesn’t have an email address set yet, but we do have one from the remote service, set the email address to that.
5. Log the user in and let the continue on their way.

rails g controller users/omniauth_callbacks
rails g controller users/registrations

## routes.rb
devise_for :users,:controllers => { omniauth_callbacks: 'users/omniauth_callbacks',registrations: 'users/registrations' }

## app/controllers/users/omniauth_callbacks.rb

class Users::OmniauthCallbacksController <      Devise::OmniauthCallbacksController

  def facebook
    generic_callback( 'facebook' )

  def twitter
    generic_callback( 'twitter' )

  def google_oauth2
    generic_callback( 'google_oauth2' )
  def generic_callback( provider )
    @identity = Identity.find_for_oauth env["omniauth.auth"]
    @user = @identity.user || current_user
    if @user.nil?
      @user = User.from_omniauth(@identity)
      @identity.update_attribute( :user_id, )
    if &&
      @user.update_attribute( :email,

    if @user.persisted?
      @identity.update_attribute( :user_id, )
       # This is because we've created the user manually, and Device expects a
       # FormUser class (with the validations)
      @user = User.find
      sign_in_and_redirect @user, event: :authentication
      set_flash_message(:notice, :success, kind: provider.capitalize) if    is_navigational_format?
      session["devise.#{provider}_data"] = env["omniauth.auth"]
      redirect_to new_user_registration_url

Override RegistrationsController to handle adding email address and password

class Users::RegistrationsController < Devise::RegistrationsController
  def update_resource(resource, params)
    if resource.encrypted_password.blank? # || params[:password].blank? = params[:email] if params[:email]
      if !params[:password].blank? && params[:password] ==    params[:password_confirmation] "Updating password"
        resource.password = params[:password]
      if resource.valid?

Adding methods to User to get to the clients

we will have to add fields of name and username to users table in order to handel twitter authentication as twitter api does not returns user email in the response hash but we get name we will apply some logic to generate an email in case of twitter authentication
rails g migration addColumnNameToUser name:string, username:string
rake db:migrate

i want to implement configrable to devise

rails g migration add_confirmable_to_devise
rake db:migrate

## db/migrate/XXXX.rb

class AddConfirmableToDevise < ActiveRecord::Migration
 def change
  add_column :users, :confirmation_token, :string
  add_column :users, :confirmed_at, :datetime
  add_column :users, :confirmation_sent_at, :datetime
  add_column :users, :unconfirmed_email, :string # Only if using reconfirmable
  add_index :users, :confirmation_token, unique: true
  # User.reset_column_information # Need for some types of updates, but not for     update_all.
  # To avoid a short time window between running the migration and updating all  existing
  # users as confirmed, do the following
  execute("UPDATE users SET confirmed_at = NOW()")


class User < ActiveRecord::Base
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :registerable,:confirmable,
    :recoverable, :rememberable, :trackable, :omniauthable,:validatable,
    :omniauth_providers => [:facebook,:google_oauth2,:twitter]
  has_many :identities
  validates_presence_of :username

  def twitter
    identities.where( :provider => "twitter" ).first

  def twitter_client
    @twitter_client ||= Twitter.client( access_token: twitter.accesstoken )

  def facebook
    identities.where( :provider => "facebook" ).first

  def facebook_client
    @facebook_client ||= Facebook.client( access_token: facebook.accesstoken )

  def google_oauth2
    identities.where( :provider => "google_oauth2" ).first

  def google_oauth2_client
    if !@google_oauth2_client
      @google_oauth2_client = => '   App', :application_version => "1.0.0" )
      @google_oauth2_client.authorization.update_token!({:access_token =>   google_oauth2.accesstoken, :refresh_token => google_oauth2.refreshtoken})

  def self.from_omniauth(identity) = # assuming the user model has a name
    user.username =" ","") # assuming the user model has a name = || "#{user.username}"
    user.password = Devise.friendly_token[0,20]
    user.skip_confirmation! false)
    return user

You can try running this sample app by just cloning it  from to you system and add the app id’s and app sectret keys in devise.rb file

Happy Coding …!


One thought on “Setting up User Authentication in Rails (Devise, Facebook,Twitter,Google)

  1. Really nice tutorial, you should update the Devise Initializer Scopes here as well like you have it on github.

    But i do have one problem. It’s currently not possible for a user to update his profile as the current password isn’t matching. So how to change this?

    Liked by 1 person

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )


Connecting to %s