Devise + OmniAuth + Facebook (what happens there)

I was curious what’s happening under the hood when facebook authentication is enabled. I specified some breakpoints in my RubyMine to find out in which order the particular methods are called.

The integration of Facebook consists of these steps: (for more information read https://github.com/plataformatec/devise/wiki/OmniAuth:-Overview):

  • adding some gems to Gemfile:

    #facebook integration
    gem 'omniauth'
    gem 'omniauth-facebook'
    gem 'omniauth-twitter'
    gem 'omniauth-linkedin'
    
  • Adding new columns to the table:

    bundle install
    rails g migration AddColumnsToUsers provider uid #note: name is already there
    rake db:migrate
    
  • make the new columns accessible (for mass assignment):

    # User model
    attr_accessible :provider, :uid
    
  • extending config by adding the facebook configuration:

    # initializers/devise.rb:
    # require the gem and add it to the config!
    
      require "omniauth-facebook"
      config.omniauth :facebook, "5745245454154", "5ecd0a644303fab5c19dfdfdf383d06", #your APP_ID and APP_SECRET
                      #for heroku necessary (development env. works as well)
                      {:strategy_class => OmniAuth::Strategies::Facebook,
                       :scope => 'email, offline_access',
                       :client_options => {:ssl => {:ca_file => '/usr/lib/ssl/certs/ca-certificates.crt'}}}
    
  • user model must have to class instance methods (see link above):

    
    #### User model must have:
    
    find_for_facebook_oauth
    find_in_session
    
  • User model must make itself “omniauthable”:

    devise : omniauthable, : omniauth_providers => [:facebook]
    
  • we need an additional controller for handling authentication provider method (facebook, twitter, …)

    #### Users controller must have a "sub controller":
    Users::OmniauthCallbacksController with facebook method.
    
  • we actually don’t need to add a link any view. The links are rendered automatically in this partial:

    /devise/shared/_links.html.erb partial
    
  • routes.rb file must be updated accordingly:

      devise_for :users, :controllers => { : omniauth_callbacks => "users/omniauth_callbacks" }
      resources :users
    

When everything is in place I can start a short debug session just to understand what’s going on and where RoR will step in.

facebook_devise_integration_sequence

I think the content of the image is self-explanatory. Devise maps the particular URLs to the actions in the controllers this way:

                    root          /                                      home#index
                    root          /                                      home#index
        new_user_session GET      /users/sign_in(.:format)               devise/sessions#new
            user_session POST     /users/sign_in(.:format)               devise/sessions#create
    destroy_user_session DELETE   /users/sign_out(.:format)              devise/sessions#destroy
           user_password POST     /users/password(.:format)              devise/passwords#create
       new_user_password GET      /users/password/new(.:format)          devise/passwords#new
      edit_user_password GET      /users/password/edit(.:format)         devise/passwords#edit
                         PUT      /users/password(.:format)              devise/passwords#update
cancel_user_registration GET      /users/cancel(.:format)                devise/registrations#cancel
       user_registration POST     /users(.:format)                       devise/registrations#create
   new_user_registration GET      /users/sign_up(.:format)               devise/registrations#new
  edit_user_registration GET      /users/edit(.:format)                  devise/registrations#edit
                         PUT      /users(.:format)                       devise/registrations#update
                         DELETE   /users(.:format)                       devise/registrations#destroy
 user_omniauth_authorize GET|POST /users/auth/:provider(.:format)        users/omniauth_callbacks#passthru {:provider=>/facebook/}
  user_omniauth_callback GET|POST /users/auth/:action/callback(.:format) users/omniauth_callbacks#(?-mix:facebook)
                   users GET      /users(.:format)                       users#index
                         POST     /users(.:format)                       users#create
                new_user GET      /users/new(.:format)                   users#new
               edit_user GET      /users/:id/edit(.:format)              users#edit
                    user GET      /users/:id(.:format)                   users#show
                         PUT      /users/:id(.:format)                   users#update
                         DELETE   /users/:id(.:format)                   users#destroy