Blog Me think, why waste time say lot word, when few word do trick

Rails API and Facebook login (featuring Doorkeeper).

When it comes to add Facebook login to Rails application there’re tons of guides and examples how to do it using Devise and Omniauth gems. That works well when you need to make it work with “classic” Rails application. But if you have Rails API application that powers your iOS/Android application it’s a bit different story.

Note: This post is only about backend part and it assumes that you know how to obtain Facebook access token (it’s described in this doc).

So that’s what we have:

  • Rails API application with protected endpoints that are accessible only by authenticated users (authenticated through Facebook).
  • iOS/Android client that does Facebook authentication and provides us users’s Facebook access token.

For user authentication we will use OAuth 2 protocol. We gonna use Doorkeeper gem to add OAuth 2 authorization support for our Rails API. By default Doorkeeper supports all common grants like Authorization code, Client credentials, Implicit grant, etc. But it doesn’t work for us. All that we going to get from mobile clients is users’s access token from Facebook. Here comes the Assertion grant. Since it’s not supported by Doorkeeper by default we need to use this doorkeeper-grants_assertion extension. That’s how the flow works:

 Party                     Client                   Token Service
   |                          |                         |
   |                          |  1) Request Assertion   |
   |                          |------------------------>|
   |                          |                         |
   |                          |  2) Assertion           |
   |                          |<------------------------|
   |    3) Assertion          |                         |
   |<-------------------------|                         |
   |                          |                         |
   |    4) OK or Failure      |                         |
   |------------------------->|                         |
   |                          |                         |
   |                          |                         |

where Relying Party is our Rails API, Client is iOS/Android app, Token Service is Facebook.

Let’s configure Doorkeeper to support that flow. That’s how your config/initializers/doorkeeper.rb might look:

Doorkeeper.configure do
  # Getting resource owner (User) from the Facebook's access token.
  resource_owner_from_assertion do[:assertion]).user!

  # Allows only assertion flow.
  grant_flows %w(assertion)

Yeah, that simple. Authentication::Facebook class is just a simple service that fetches the user information using Facebook’s access token and tries to create a new user or return existing one based on user’s Facebook id. It might look like this:

require 'net/http'

module Authentication
  class Facebook
    FACEBOOK_USER_FIELDS = 'id,name,first_name,last_name'

    def initialize(access_token)
      @access_token = access_token

    def user!
      return if user_data.blank? || facebook_id.blank?

      User.find_by(facebook_id: facebook_id) || create_user!


    def create_user!
        facebook_id: facebook_id,
        first_name: first_name,
        last_name: last_name

    def user_data
      @user_data ||= begin
        response = Net::HTTP.get_response(request_uri)

    def facebook_id

    def first_name

    def last_name

    def request_uri

That’s basically it. Finally, you can test that everything works by making a request to our Rails API:

curl -X POST \
  http://localhost:3000/oauth/token \
  -d 'client_id=OAUTH_CLIENT_ID&grant_type=assertion&assertion=YOUR_FACEBOOK_ACCESS_TOKEN'

where OAUTH_CLIENT_ID is your id of Doorkeeper’s OAuth Application (you can read more about it here), YOUR_FACEBOOK_ACCESS_TOKEN is your Facebook access token (just to test, you can generate it in Facebook’s Graph API Explorer). After running that request you’ll get something like:


It works! Here’s the access_token you can use to do authorized requests to your endpoints!