Single Sign-On with Facebook & Ruby on Rails

There are over 400 Million people on earth with a Facebook Account. From this point of view it makes absolute sense to offer a Single Sign-On with Facebook.

Facebook offers a Login via OAuth 2.0. The Facebook documentation for the Authentication process you can find here: http://developers.facebook.com/docs/authentication/.

Before you are using the API from Facebook you have to set up an “Facebook App”. Every Facebook App has a client_id and a client_secret. You need both to communicate with the Facebook API. Here you can create a Facebook App: http://www.facebook.com/developers/

If your set up is done you can start with the implementation. Maybe you want to offer a “Login with Facebook” button like this:

Login with Facebook
Login with Facebook

To achieve this you can embed this code in your HTML Page:

<pre><a href='javascript:var popupWindow = window.open(link, "popupWindow", "toolbar=no, location=no, directories=no, status=no, menubar=no, scrollbars=no, menubar=1, resizable=1, width="+winWidth+",height="+winHeigh+"top="+top+", left="+left);'
           style="margin-right: 5px;" >
    <img src="/images/fb_login_icon.gif"  style="border: 0px solid white; padding: 0;" />
</a></pre>

This will open a JavaScript popup window with the Facebook Login mask, if you are not already logged in by Facebook via Cookie.

To make this work you need a little bit JavaScript:

var winWidth = 950;
var winHeigh = 550;
var left = (screen.width/2)-(winWidth/2);
var top = (screen.height/2)-(winHeigh/2);

var domainlink = "https://graph.facebook.com/oauth/authorize?";
var req_perms = "req_perms=email&";
var clientid = "client_id=111111111111&";
var scope = "scope=email,offline_access&";
var redirect = "redirect_uri=http://yourdomain.com/facebook/start";
var link = domainlink + req_perms + clientid + scope + redirect;

Just replace  “111111111111” with your client_id and “yourdomain” with your domain. The link contains a redirect_uri on your server. After the Facebook Authentication is done, Facebook will redirect the user to your “redirect_uri”.

OK. And here is the corresponding Controller with Ruby on Rails.

class FacebookController < ApplicationController

  layout "plain"

  def start
    code = params['code']

    domain = 'https://graph.facebook.com'
    uri = '/oauth/access_token'
    query = 'client_id=111111111111&'
    query += 'redirect_uri=http://yourdomain.com/facebook/start&'
    query += 'client_secret=2222222222222222222&'
    query += 'code=' + code
    link = domain + uri + '?' + query

    response = HTTParty.get(URI.encode(link))

    data = response.body
    access_token = data.split("=")[1]

    user = get_user_for_token access_token
    if !user.nil?
      sign_in user
    end
  end

  private

    def get_user_for_token(token)
      json_user = JSON.parse HTTParty.get('https://graph.facebook.com/me?access_token=' + URI.escape(token)).response.body
      user = User.find_by_fb_id json_user['id']
      if user.nil?
        user = User.new
        user.update_from_fb_json json_user
      end
      user.fb_token = token
      user.save
      user
    end

end

I am using here the “HTTParty” gem. You should have this line in your Gemfile:

gem 'httparty', '0.7.4'

And you have to map the controller action in your routes.rb file:

match '/facebook/start',    :to => 'facebook#start'

The “def start” action will be called from Facebook after the User Auth.  Facebook will send you with this request a “code”. You can fetch the code like this:

code = params['code']

Together with the given token, your client_id and your client_secret you can fetch an access_token from facebooks GRAPH API.

    domain = 'https://graph.facebook.com'
    uri = '/oauth/access_token'
    query = 'client_id=111111111111&'
    query += 'redirect_uri=http://yourdomain.com/facebook/start&'
    query += 'client_secret=2222222222222222222&'
    query += 'code=' + code
    link = domain + uri + '?' + query

    response = HTTParty.get(URI.encode(link))

    data = response.body
    access_token = data.split("=")[1]

With the access_token you can fetch a user as JSON object.

json_user = JSON.parse HTTParty.get('https://graph.facebook.com/me?access_token=' + URI.escape(token)).response.body

That’s it.

Leave a Reply

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

WordPress.com Logo

You are commenting using your WordPress.com 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 )

Google+ photo

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

Connecting to %s