A Beginner’s Guide to Using the Facebook API in Your Rails Application

I recently built a web application that was heavily reliant on the Facebook API, from authentication to the app’s core functionality, so I thought I would share the process that got me up and running in a central location. There are a lot of resources out there, and a lot of different ways to leverage the Facebook API. The focus of this post will be step 1, authentication.

Before We Begin

The first thing you have to do when preparing to use the Facebook API is register as a developer and create a Facebook application. Each application has a unique App ID and an App Secret which you need to keep track of in order to make the API calls. In the app dashboard you will also find your advanced settings. Here, you can add the authorized redirect URLs needed for your Rails application. During development this will likely be localhost:port (or wherever you are running your server), but you will also need to add staging or production URLs when the time comes.

Once you have completed the initial setup and have acquired the necessary keys, you can begin to implement an authentication flow.

Using the Facebook API in Your Rails Application

Authentication

Social media authentication has quickly become a standard option for nearly every kind of software, and Facebook makes it fairly easy to use. You’ve definitely seen the default “Login with Facebook” button. There are a number of ways you can go about creating the login flow, but I prefer the server side method using omniauth + the omniauth-facebook strategy gems.

With these you can setup everything your authentication call needs in an initializer and keep your views much cleaner. Note: It is good practice to use ENV variables here for your keys as they will not be exposed this way.

/config/initializers/omniauth.rb 
    Rails.application.config.middleware.use OmniAuth::Builder do
      provider :facebook, ENV["FACEBOOK_KEY"], ENV["FACEBOOK_SECRET"],
      scope: email,manage_pages,publish_actions
    end

The scope parameter is optional, and specifies what permissions you would like your authentication to request. A list of all possible permissions and their uses can be found here. The above code will be used with a view that has a simple “Login with Facebook” link that hits the /users/auth/facebook url.

/views/devise/sessions/new/html.erb   
    <a href="<%= user_omniauth_authorize_path(:facebook) %>" class="button">
      Sign in with Facebook
    </a>

Response

Once the user has successfully entered their Facebook account credentials and approved the requested permissions, a response is sent back to the redirect URL specified in the app’s advanced settings. This response is handled in the the OmniauthCallbacksController and the User class:

/controllers/omniauth_callbacks_controller.rb
    def facebook
      user = User.from_omniauth(request.env["omniauth.auth"])
      if user.persisted?
        sign_in_and_redirect user
      else
        redirect_to unauthenticated_root_path
      end
    end

    def after_sign_in_path_for(user)
      authenticated_root_path
    end
/models/user.rb
    devise :omniauthable, :omniauth_providers => [:facebook]
  
    def self.from_omniauth(auth)
      where(provider: auth.provider, uid: auth.uid).first_or_create do |user|
        user.build_profile_from_omniauth(auth) if user.new_record?
      end
    end
    
    def build_profile_from_omniauth(auth)
      self.provider = auth.provider
      self.uid = auth.uid
      self.token_expires_at = auth.credentials.expires_at
      self.email = auth.info.email
      self.facebook_token = auth.credentials.token
      self
    end

Depending on what information you request, the request.env[“omniauth.auth”] will look something like:

{
    :provider => 'facebook',
    :uid => '1234567',
    :info => {
      :email => 'jdoe@gmail.com',
      :name => John Doe',
      :first_name => 'John',
      :last_name => 'Doe',
      :verified => true
    },
    :credentials => {
      :token => 'ABCDEF...',
      :expires_at => 1321747205,
      :expires => true
    }
  }

In general, I like to build a user’s basic information from the returned data. I’ve created two methods on the User model that are called when a user logs into the app.

The first method uses the provider and UID in the returned hash to check the database to see if we already have a user that matches those credentials. If we do, it simply returns that user, otherwise it calls the second method that updates a user’s attributes based on whatever fields I choose to use before returning that new user.

The two most important of those fields, especially moving beyond authentication, are the token and the expires_at(time from now in seconds, generally ~ 60 days). The reason for saving the token is so that we can use that same token to make API calls to perform actions around the permissions we requested at the beginning of the authentication. The latter is important because it allows us to build a workflow for exchanging a token before it expires so that we always have a valid token. Note: the token expires_at field is only returned the first time the token is generated and not on subsequent logins, so be sure to capture it from the get-go.

Following these steps will get you using Facebook authentication to sign in to your rails app in no time. The Facebook developer documentation as well as the READMEs for both of the gems I used are both extensive and helpful if you are looking to get a bit more creative with your login flow.

More Posts by Nick Schello: