OmniAuth for external authentication with rails

QED42   |  12th July, 2012

Omniauth is a pretty simple solution if you want your users to authenticate using oauth and openid providers. Its based on the principle that 

Every authentication system can essentially be boiled down into two "phases".

  1. Request phase : we request information from the user that is necessary to complete authentication. This information may be POSTed to a URL or performed externally through an authentication process such as OpenID.
  2. Callback phase : In the Callback Phase, we receive an authenticated unique identifier that can differentiate this user from other users of the same authentication system. Additionally, we may provide user information that can be automatically harvested by the application to fill in the details of the authenticating user.

Omniauth doesn't handle your session, it mainly focuses on bringing you the required data from the provider and its upto you to manage the session. You can use any authentication system in rails to do that e.g devise, restful_authentication, authlogic etc. OmniAuth is the best solution for seamless integration of multiple authentication providers.

The Omniauth library was released by intridea and is a Rack based authentication system.

Idea

User is sent to /auth/:provider (provider can be twitter, facebook or any other), where he authenticates using the provider, and he returns to the callback url which is always /auth/:provider/callback. You just have to map /auth/:provider/callback to a controller action, where you get the response data in a hash.

Implementation

Include config.gem "omniauth" in your environment.rb file and run rake gems:install. You might get "libxml" missing, for that you should do apt-get for libxslt-dev and libxml3-dev. This should install omniauth.

Create config/initializers/omniauth.rb. You can choose from the list of providers

Generate the Authorization model.

script/generate model authorization provider:string uid:string user_id:integer
rake db:migrate

This is how your model should look like. In the authorization model, we are storing the provider, unique id of the user within the provider and the user_id. The combination of provider and the uid is always unique.

Create a route for the callback url. In the "create" method of authorization controller we handle the data received from provider. (you can handle this in any controller, action). If the user denies giving access to his information, it will be routed back to /auth/failure. So make sure you have defined a path for that as well.

map.callback "/auth/:provider/callback", :controller => "authorizations", :action => "create"
map.failure "/auth/failure", :controller => "authorizations", :action => "failure"

In the authorization controller  define the "create", "failure" and "destroy" methods.

The current_user method used above returns the user in the current session. The create method does the job of

  1. Collecting the information sent by the provider (which is available in request.env['rack.auth'])
  2. Checks if the user has already authorized using the provider. If he has not and is logged in, it will associate the provider with users current account.
  3. It will create a new account if the user is registering for the first time with oauth and openid providers

You need a few methods in the authorization model to find and create authorizations.

In the user model

Thats it! This is the set up you need. Here is the demo of omniauth configured with authlogic for rails 2.3.x and its full source code

Resources :

Railscasts Episode 235: OmniAuth Part 1
Railscasts Episode 236: OmniAuth Part 2
Separating Authentication and Identity with OmniAuth
Omniauth wiki

Looking for a Drupal partner ?

We are drupal 8 ready