Authlogic OAuth2

Disclaimer: This plugin CANNOT be used alongside other Authlogic extensions like authlogic_oauth and authlogic_openid due to an unfortunate bug caused by all these plugins overriding the ActiveRecord save method to avoid a DoubleRenderError.

Install and use

1. Install the authlogic and oauth2 gems

config.gem "authlogic"
config.gem "oauth2"
config.gem "authlogic_oauth2"

$ sudo rake gems:install

For older version of Rails, you can install authlogic_oauth2 as a plugin:

$ script/plugin install git://github.com/andyhite/authlogic_oauth2.git

2. Set up and configure authlogic

For information about how to set up and configure authlogic, please consult the authlogic README (github.com/binarylogic/authlogic)

3. Add the necessary fields to your authlogic users table

class AddOauth2FieldsToUser < ActiveRecord::Migration
  def self.up
    add_column :users, :oauth2_token, :string
    add_index :users, :oauth2_token
  end

  def self.down
    remove_column :users, :oauth2_token
  end
end

IMPORTANT: make sure that you allow null values for crypted_password and password_salt if they aren’t required for OAuth2 users.

4. Configure your OAuth2 client in the UserSession model

The oauth2_client_id, oauth2_client_secret and oauth2_site configuration values must be specified so we can initialize the connection with your OAuth2 provider. The oauth2_scope value is optional, and is used to request extended permissions from your provider.

Here’s an example for Facebook:

class UserSession < Authlogic::Session::Base
  oauth2_client_id      "APPLICATION_ID"
  oauth2_client_secret  "APPLICATION_SECRET"
  oauth2_site           "https://graph.facebook.com"
  oauth2_scope          "offline_access,email,user_birthday"
  oauth2_cannot_find_record_message "We have no record of you in our database, please sign up first."
end

It’s important to note here that if you don’t request offline_access permissions from your OAuth2 provider the access token will expire either at a specific time or upon logout from the provider itself. Some providers allow refresh tokens to be issued, but some (Facebook, for example) does not. Refresh token handling hasn’t been implemented in authlogic_oauth2 yet, so make sure you request offline_access.

5. Make sure you save your objects properly

We need to redirect the user to their oauth2 provider so they can authenticate and then pick things back up when they’re returned, so any calls to User#save or UserSession#save need to be updated to the following format:

@user.save do |result|
  if result
    # Do something
  else
    # Do something else
  end
end

and

@user_session.save do |result|
  if result
    # Do something
  else
    # Do something else
  end
end

6. Add the login and register buttons to their respective forms

In file app/views/user_sessions/new.html.erb:

<% form_for @user_session, :url => user_session_path do |f| %>
  # All your other form stuff goes here, if you need it.
  <%= oauth2_login_button :value => "Login using Facebook" %>
<% end %>

In file app/views/users/new.html.erb:

<% form_for @user, :url => account_path do |f| %>
  # All your other form stuff goes here, if you need it.
  <%= oauth2_register_button :value => "Register using Facebook" %>
<% end %>

7. There is no step 7

If you followed these steps correctly, then you should be able to register and login using OAuth2.

Accessing API endpoints

You can easily access any API endpoints that are exposed to an OAuth2 user by utilizing the oauth2 gem’s “get” method on current_user#oauth2_access. For instance, you can access information about the currently logged in user’s Facebook profile by doing the following:

current_user.oauth2_access.get('/me')

This will return a JSON string representing the user’s profile information.

You can pre-populate user information by using the after_oauth2_authentication hook in your user model:

require 'json'

class User < ActiveRecord::Base
  ...

  def after_oauth2_authentication
    json = oauth2_access.get('/me')

    if user_data = JSON.parse(json)
      self.name = user_data['name']
      self.facebook_uid = user_data['id']
    end
  end
end

You can get more information about the Facebook Graph API on the following website: developers.facebook.com/docs/api