Facebook OAuth using OmniAuth and Rails 4

Posted on Oct 21, 2013

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']

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


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
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)


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

  def create
    auth = Authentication.from_omniauth(current_user, env["omniauth.auth"])
    flash[:notice] = "Authentication successful."
    redirect_to authentications_url

  def destroy
    @authentication = current_user.authentications.find(params[:id])
    flash[:notice] = "Successfully destroyed authentication."
    redirect_to authentications_url

// Additional JS functions here
window.fbAsyncInit = function() {
    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
   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);

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" %>
      <% end %>
      <div class="clear"></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" %>
<% 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" %>

<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