Using OmniAuth to make Twitter/oAuth API requests

Posted: 2010-11-16
Category: Rails

Using the brilliant user system gem Devise and a gem called OmniAuth you can make a Rails application that logs in or registers users via Twitter, Facebook, Gowalla, etc with amazing ease. But once the user is logged in, how do you go about actually interacting with the API on behalf of the account that has just been authorized?

This article starts where RailsCasts leaves off, so if you are not already up and running with Devise and OmniAuth then you might want to watch:

So, assuming we are all about at the point that the third video ends on, we are all ready to go. I'll be using the example of Twitter but really any of the providers using oAuth will use the same approach. Like in the "ye-olden days" when we used the Twitter username and password to authenticate an API request, we now use a Access Token and Token Secret. You can think of these as being basically the same thing as for the purpose of authenticating API requests, to us, they are.

To get the token and secret you need to add some fields to your authentications table:


rails g migration AddTokenToAuthentications token:string secret:string
rake db:migrate

Now the database is ready to save the credentials we can change the authentication code to populate the fields. Assuming you placed the method in user.rb like RailsCast #236: OmniAuth Part 2 suggested then open user.rb and modify the following line:

authentications.build(:provider => omniauth['provider'], :uid => omniauth['uid'])

and replace it with:

authentications.build(
    :provider => omniauth['provider'],
    :uid => omniauth['uid'],
    :token => omniauth['credentials']['token'],
    :secret => omniauth['credentials']['secret']
)

Now whenever anybody authenticates their account we can save their credentials which are passed back from the internal hidden magic that is OmniAuth.

The next step is to actually make some requests using these saved credentials, which is described almost perfectly in the Twitter Developer Documentation. You'll want to install the oauth gem (put it in your Gemfile and run bundle install) then you can use the following code to test-dump a list of tweets from the user:

class TwitterController < ApplicationController

    def recent_tweets
        # Exchange your oauth_token and oauth_token_secret for an AccessToken instance.

        def prepare_access_token(oauth_token, oauth_token_secret)
            consumer = OAuth::Consumer.new("APIKey", "APISecret"
                { :site => "http://api.twitter.com"
                })
            # now create the access token object from passed values
            token_hash = { :oauth_token => oauth_token,
                                         :oauth_token_secret => oauth_token_secret
                                     }
            access_token = OAuth::AccessToken.from_hash(consumer, token_hash )
            return access_token
        end

        auth = current_user.authentications.find(:first, :conditions => { :provider => 'twitter' })

        # Exchange our oauth_token and oauth_token secret for the AccessToken instance.
        access_token = prepare_access_token(auth['token'], auth['secret'])

        # use the access token as an agent to get the home timeline
        response = access_token.request(:get, "http://api.twitter.com/1/statuses/user_timeline.json")

        render :json => response.body
    end
end

By pulling the content from current_user.authentications (im finding the first as in my application they should only have one) I can grab the credentials and have full permissions to get their recent tweets, post new ones, see friends tweets, etc.

Now I can tweak this, get stuff saved, faff with the JSON and take what I need. Working with Facebook or any other oAuth provider will work in an almost identical way, or you can install specific gems to interact with their API's if the direct approach is not as smooth as you'd like.

Comments

Gravatar
Michael Grech

2010-11-26

Working w/ rails lately eh? I remember seeing that on your 'Goals' list. Hopefully you don't forget about 'Fuel' though, the PHP world needs ppl like you Phil! BTW using your CI migrations code nice work. Oh and I looked through the source for Fuel the other day, good work there too hopefully the project will take off and replace CI :)

Keep em coming Phil!

Gravatar
Ved Antani

2010-12-26

Dont you think we will need to change the following line also in authentication_controller.rb ? otherwise new authentications will have null tokens and secrets:

current_user.authentications.create!(:provider => omniauth['provider'], :uid => omniauth['uid'], omniauth['credentials']['token'],omniauth['credentials']['secret'])

Gravatar

2010-12-31

Yes indeed Ved, I forgot to post this ammendment after I discovered the bug.

The code I posted works with new users registering via a provider, but fails for existing users authenticating with new providers. Thank you for reminding me. :)

Gravatar
Tim

2011-01-19

How would I use omniauth to request permissions from facebook?

Gravatar
Dave

2011-02-16

Should the access token be saved? Or can the token/secret saved in the Authentications table be used to request new access tokens on a per-session basis?

Gravatar
Dave

2011-02-16

Nevermind, I see now that the token/secret saved is the access token. I thought it was the unauthorized request token...

Gravatar
Lady

2011-11-27

Tanks for good post!

Posting comments after three months has been disabled.