As I discussed my experience developing an application in Rails 3 using authlogic and omniauth in my last post, Here is the tutorial as promised.
Step 1:
First of all you need to setup a Rails 3 application using authlogic gem. If you’re feeling some difficulty, try these tutorials for help:
Authlogic railcasts: http://railscasts.com/episodes/160-authlogic
Authlogic with Rails 3 tutorial: http://www.dixis.com/?p=352
Step 2:
Add the following line to your gemfile:
gem 'omniauth'
and then install the bundle
bundle install
Step 3:
Now create a ruby file in config/initializers. I’ve named it as omniauth.rb. Put the following code in it:
Rails.application.config.middleware.use OmniAuth::Builder do provider :twitter, 'CONSUMER_KEY', 'CONSUMER_SECRET' provider :facebook, 'APP_ID', 'APP_SECRET' # Mention other providers here you want to allow user to sign in with end
* You can get the keys by creating an application on twitter and facebook each.
Step 4:
A user can be authenticated e.g., for twitter by redirecting him to:
http://HOST:PORT/auth/twitter
After authentication, user will be redirected back to
http://HOST:PORT/auth/twitter/callback
We can handle this callback and redirect user to a controller#action where we can process his registration and/or session handling as well as can fetch some useful data. For this, add the following lines in your routes.rb file:
resources :authentications match '/auth/:provider/callback' => 'authentications#create'
Let’s add a couple of links on our login page which allow user to sign in via facebook or twitter:
<a href="/auth/twitter">Sign in with Facebook</a> <a href="/auth/facebook">Sign in with Twitter</a>
Step 5:
Until here, we’ve nicely setup the user part of authentication. Now we’ve to handle the callback from social websites after authentication. Create a scaffold authentication. Here are required code snippets:
Authetications Migration:
class CreateAuthentications < ActiveRecord::Migration def self.up create_table :authentications do |t| t.integer :user_id t.string :provider t.string :uid t.timestamps end end def self.down drop_table :authentications end end
Authentication Model:
class Authentication < ActiveRecord::Base belongs_to :user validates :user_id, :uid, :provider, :presence => true validates_uniqueness_of :uid, :scope => :provider end
Step 6:
And lastly, the authentications controller will be contain following code:
class AuthenticationsController < ApplicationController def create omniauth = request.env['omniauth.auth'] authentication = Authentication.find_by_provider_and_uid(omniauth['provider'], omniauth['uid']) if authentication # User is already registered with application flash[:info] = 'Signed in successfully.' sign_in_and_redirect(authentication.user) elsif current_user # User is signed in but has not already authenticated with this social network current_user.authentications.create!(:provider => omniauth['provider'], :uid => omniauth['uid']) current_user.apply_omniauth(omniauth) current_user.save flash[:info] = 'Authentication successful.' redirect_to home_url else # User is new to this application user = User.new user.authentications.build(:provider => omniauth['provider'], :uid => omniauth['uid']) user.apply_omniauth(omniauth) if user.save flash[:info] = 'User created and signed in successfully.' sign_in_and_redirect(user) else session[:omniauth] = omniauth.except('extra') redirect_to signup_path end end end def destroy @authentication = current_user.authentications.find(params[:id]) @authentication.destroy flash[:notice] = 'Successfully destroyed authentication.' redirect_to authentications_url end private def sign_in_and_redirect(user) unless current_user user_session = UserSession.new(User.find_by_single_access_token(user.single_access_token)) user_session.save end redirect_to home_path end end
Step 7:
Update your user model and add following lines in it:
def apply_omniauth(omniauth) self.email = omniauth['user_info']['email'] # Update user info fetching from social network case omniauth['provider'] when 'facebook' # fetch extra user info from facebook when 'twitter' # fetch extra user info from twitter end end
And here your go. You application is all ready for authentication with facebook and twitter. And yes, you can also register/signin using conventional email and password technique.
Interesting Fact:
The application that we’ve coded above not only supports one-time user registration using social networks. It also supports multiple social accounts for a single user. Yes, you read that right.
Remember, we have separate authentications table. So a user can have more than 1 way of entering in the site. How to do this? Well, it’s as simple as reading this line. Once the user is signed in, you can redirect him again to the paths we used initially for signing him in. That is, you can write these lines again in your user’s homepage
<a href="/auth/twitter">Sign in with Facebook</a> <a href="/auth/facebook">Sign in with Twitter</a>
and he’ll have multiple social accounts associated with same user. Of course, you can hide the links of those networks user has already connected with his account.
How is this done?
Go though the code of the authentications controller again. We’ve a nice little condition there:
elsif current_user # User is signed in but has not already authenticated with this social network current_user.authentications.create!(:provider => omniauth['provider'], :uid => omniauth['uid']) current_user.apply_omniauth(omniauth) current_user.save
In case user is signed in, another authentication will be added for him and that’s all. Try to logout and login with newly added network. Yes, it meant to be as easy as 1,2,3…
Share the post if you liked it and it helped you.