Facebook OAuth using OmniAuth and Rails 4
Step 1: Installing gems
gem "omniauth"
gem 'omniauth-facebook', '1.4.0'
bundle install
Step 2
OmniAuth.config.logger = Rails.logger
Rails.application.config.middleware.use OmniAuth::Builder do
provider :facebook, ENV['FACEBOOK_KEY'], ENV['FACEBOOK_SECRET']
end
Step 1: An app
Mine looked like this:
Click “Continue”, and you should be brought to an application screen that contains your App ID (or API Key) and your App Secret. Note those, but we’ll need to fill in some information here.
In the “App Domains” box, put ’localhost'
Click the green check on “Website with Facebook Login”, and fill that in with http://localhost:5000/. My students (or anyone who uses my Rails templates) will be able to use this. This value may be different for you– make sure that it matches whatever you use in development. localhost:3000 would be common if you are using rails s and appname.dev would be likely if you were using Pow.
Mine looked like this
Step 2: Installing application details
FACEBOOK_KEY=686338067928534
FACEBOOK_SECRET=60b9fe21ab431897eabc0743b39a5406
Step 1: Create a model to store the authentications
bundle exec rails g model Authentication user_id:integer provider:string uid:string name:string oauth_token:string oauth_expires_at:datetime
class CreateAuthentications < ActiveRecord::Migration
def change
create_table :authentications do |t|
t.integer :user_id
t.string :provider
t.string :uid
t.string :name
t.string :oauth_token
t.datetime :oauth_expires_at
t.timestamps
end
end
end
class Authentication < ActiveRecord::Base
belongs_to :user
def self.from_omniauth(user, auth)
where(auth.slice(:provider, :uid)).first_or_initialize.tap do |authentication|
authentication.user = user
authentication.provider = auth.provider
authentication.uid = auth.uid
authentication.name = auth.info.name
authentication.oauth_token = auth.credentials.token
authentication.oauth_expires_at = Time.at(auth.credentials.expires_at)
authentication.save!
end
end
end
Step 2: Create the authentication user interface
bundle exec rails g controller authentications index
class AuthenticationsController < ApplicationController
def index
@authentications = current_user.authentications if current_user
end
def create
auth = Authentication.from_omniauth(current_user, env["omniauth.auth"])
flash[:notice] = "Authentication successful."
redirect_to authentications_url
end
def destroy
@authentication = current_user.authentications.find(params[:id])
@authentication.destroy
flash[:notice] = "Successfully destroyed authentication."
redirect_to authentications_url
end
end
// Additional JS functions here
window.fbAsyncInit = function() {
FB.init({
appId : 686338067928534, // App ID
status : true, // check login status
cookie : true, // enable cookies to allow the server to access the session
xfbml : true // parse XFBML
});
};
// Load the SDK Asynchronously
(function(d){
var js, id = 'facebook-jssdk', ref = d.getElementsByTagName('script')[0];
if (d.getElementById(id)) {return;}
js = d.createElement('script'); js.id = id; js.async = true;
js.src = "//connect.facebook.net/en_US/all.js";
ref.parentNode.insertBefore(js, ref);
}(document));
function fblogin() {
FB.getLoginStatus(function(response) {
if(response.status == "connected") {
location.href =
'/auth/facebook/callback?' +
$.param({ signed_request: response.authResponse.signedRequest })
} else {
FB.login(function(response) {
if (response.authResponse) {
'/auth/facebook/callback?' +
$.param({ signed_request: response.authResponse.signedRequest })
}
})
}
})
};
<% if @authentications %>
<% unless @authentications.empty? %>
<p><strong>You can sign in to this account using:</strong></p>
<div class="authentications">
<% for authentication in @authentications %>
<div class="authentication">
<%= image_tag "#{authentication.provider}_32.png", :size => "32x32" %>
<div class="provider"><%= authentication.provider.titleize %></div>
<div class="uid"><%= authentication.uid %></div>
<%= link_to "X", authentication, :confirm => 'Are you sure you want to remove this authentication option?', :method => :delete, :class => "remove" %>
</div>
<% end %>
<div class="clear"></div>
</div>
<% end %>
<p><strong>Add another service to sign in with:</strong></p>
<% else %>
<p><strong>Sign in through one of these services:</strong></p>
<% end %>
<!--
<a href="/auth/twitter" class="auth_provider">
<%= image_tag "twitter_64.png", :size => "64x64", :alt => "Twitter" %>
Twitter
</a>
-->
<% unless @authentications.select{ |a| a.provider == "facebook" }.any? %>
<%= link_to_function image_tag("facebook_64.png", :size => "64x64", :alt => "Facebook"), 'fblogin()' %>
<% end %>
<!--
<a href="/auth/google_apps" class="auth_provider">
<%= image_tag "google_64.png", :size => "64x64", :alt => "Google" %>
Google
</a>
-->
<div class="clear"></div>
.authentications {
margin-bottom: 30px;
}
.authentication {
width: 130px;
float: left;
background-color: #EEE;
border: solid 1px #999;
padding: 5px 10px;
-moz-border-radius: 8px;
-webkit-border-radius: 8px;
position: relative;
margin-right: 10px;
}
.authentication .remove {
text-decoration: none;
position: absolute;
top: 3px;
right: 3px;
color: #333;
padding: 2px 4px;
font-size: 10px;
}
.authentication .remove:hover {
color: #CCC;
background-color: #777;
-moz-border-radius: 6px;
-webkit-border-radius: 6px;
}
.authentication img {
float: left;
margin-right: 10px;
}
.authentication .provider {
font-weight: bold;
}
.authentication .uid {
color: #666;
font-size: 11px;
}
.auth_provider img {
display: block;
}
.auth_provider {
float: left;
text-decoration: none;
margin-right: 20px;
text-align: center;
margin-bottom: 10px;
}
Step 3: Putting it all together
resources :authentications
match 'auth/:provider/callback', to: 'authentications#create', via: [:get, :post]
match 'auth/failure', to: redirect('/'), via: [:get, :post]
//= require facebook
@import "authentications";
<%= link_to "Social Accounts", authentications_path %>
curl -o app/assets/images/facebook_32.png https://www.evernote.com/shard/s1/sh/c3303305-ff8f-4829-a315-9ee91709f479/49b3985624af8fb0cae8e3223333c61a/deep/0/facebook_32.png
cp app/assets/images/facebook_32.png app/assets/images/facebook_64.png
Step 4: Boot it up
bundle exec foreman start