oAuth with the Twitter API in Ruby on Rails without a gem

15th December, 2011 - Posted by david

This post is a follow on from my previous post about the oAuth protocol in general in Ruby. Here I detail how to let a user authenticate themselves via Twitter to your web app, request a list of people they’re following (a GET operation) and how to follow a specific user (a POST operation). As this is a follow-on from an earlier post, the following functions used here can be seen there:

  • params(consumer_key)
  • generate_nonce(size)
  • signature_base_string(method, uri, params)
  • url_encode(string)
  • sign(key, base_string)
  • header(params)
  • request_data(header, base_uri, method, post_data=nil)

The Log-in Process

When you sign up for an API key from Twitter, Yelp etc. you’ll be given a Consumer Key and a Consumer Secret. You may also be given an Access Token and an Access Token secret, but that’s for you logging into your own account. If that’s all you wish to do, you can skip this section.

So, if you want to let a user log in to their Twitter (or whatever) account via your site, you need to get an access token. The process for this is as follows:

  1. You request a unique Request Token from Twitter for your ‘Log-in with Twitter’ button
  2. You use this request token, as well as where on your site you want the user to be re-directed back to after they’re authenticated, to build the URL the button points to
  3. They click the ‘Log-in with Twitter’ button on your site
  4. The user is brought to Twitter where they enter their username and password
  5. Twitter re-directs them back to your site, to the URL you gave them in step 2
  6. Back at your site, you’ll now have an oAuth verifier
  7. This can be used to get the user’s Twitter user info, which has been authenticated by Twitter

Step 1: Getting an oAuth request token for your current session

Twitter’s URL for getting a request token from is https://api.twitter.com/oauth/request_token. The request for the token contains a number of parameters, which are then combined with the URL you’re going to be sending the data to and the method of your request (i.e. GET, POST etc.) to generate what’s called a base signature. At this point you don’t have an access token, so your signing key is simply your consumer secret followed by an ‘&‘. Using the functions I’ve mentioned earlier, this can be done as follows:

consumer_key = 'abcdefghijklmnop' # Obtainable from your destination site's API admin panel
consumer_secret = 'zyxwvutsrqponm' # As above
callback_url = 'http://www.mysite.com/logged-in'
method = 'POST'
uri = 'https://api.twitter.com/oauth/request_token'
params = params(consumer_key)
params['oauth_callback'] = url_encode(callback_url)
params['oauth_signature'] = url_encode(sign(consumer_secret + '&', signature_base_string(method, uri, params)))
token_data = parse_string(request_data(header(params), uri, method))
auth_token, auth_token_secret = [token_data['oauth_token'], token_data['oauth_token_secret']] # save these values, they'll be used again later

# where parse_string is simply
def parse_string(str)
  ret = {}
  str.split('&').each do |pair|
    key_and_val = pair.split('=')
    ret[key_and_val[0]] = key_and_val[1]
  end
  ret
end

Steps 2-5: Authenticating with Twitter

Once you have your request/access token, the URL to direct your user to is simply:

login_url = 'https://api.twitter.com/oauth/authorize?oauth_token='+auth_token

You can use standard <%= link_to 'Login', @login_url %> to generate a HTML anchor in your ERB template or whatever you choose. The user will then be directed to Twitter, where they enter their log-in details and get directed back to your callback URL.

Steps 6-7: Getting the user’s info

When the user is directed back to your site, you’ll be sent an oauth_verifier. This can be obtained via Rails in your callback URL’s corresponding controller, via params[:oauth_verifier]. You need to use this to request their user info, as a final check before they’re fully logged in. This results in a new auth token (or what Twitter calls an access token) and auth token secret, which should replace your previous stored values. It is assumed the code below is stored in a model class, where you need to pass the auth verifier from your controller.

method = 'POST'
base_uri = 'https://api.twitter.com/oauth/access_token'
params = params() # not to be confused with params in your controller
params['oauth_verifier'] = auth_verifier # this does come from params in the controller
#auth_token_secret here is from above
params['oauth_signature'] = url_encode(sign(consumer_secret + '&' + auth_token_secret, signature_base_string(method, uri, params)))
data = parse_string(request_data(header(params), base_uri, method))

data will now contain an array with things such as screen_name, user_id etc. of the user who just logged in. It’ll also contain a new oauth_token and oauth_token_secret, which should be saved as they’ll be used again.

Now you have a fully validated user, who has authenticated you to access information on Twitter via their Twitter account. So now, let’s access some of that info.

Getting the people a user is following (a GET request)

The process for all GET requests is pretty similar and roughly follows what we’ve done before. We have our array of standard parameters. To this, each of the GET parameters are passed. We use our access token and consumer key & secret to generate our oAuth signature, make the request and parse the response.

method = 'GET'
uri = 'https://api.twitter.com/1/friends/ids.json'
params = params(consumer_key)
# Add the GET parameters here
params['cursor'] = '-1' # start at the beginning
params['user_id'] = user_id # from 'data' array above
params['oauth_signature'] = url_encode(sign(consumer_secret + '&' + auth_token_secret, signature_base_string(method, uri, params)))
uri += '?cursor=-1&user_id=' + user_id # Add in the GET parameters to the URL
followees = JSON.parse(request_data(header(params), uri, method))

Following a specific user (a POST request)

The process for a POST is pretty similar, the only difference being how you handle the parameters to the request. In the example below, I’m assuming you have the user ID of the person you want to follow and that it’s stored in a variable called followee_user_id.

method = 'POST'
uri = 'https://api.twitter.com/1/friendships/create.json'
params = params(consumer_key)
params['user_id'] = followee_user_id
params['oauth_signature'] = url_encode(sign(consumer_secret + '&' + auth_token_secret, signature_base_string(method, uri, params)))
resp = JSON.parse(request_data(header(params), uri, method, 'user_id='+followee_user_id))

So, assuming that was successful, the user should now be following the person with user ID followee_user_id.

Conclusion

Hopefully this will fill in some of the gaps in Twitter’s documentation. When coding this I found plenty of instances where the documentation would say something like “now sign the key”, without actually telling you how to sign it! Very confusing indeed.

Disclaimer: I obviously wrote all this in proper Ruby on Rails classes and controllers, but have extracted the code out here to be presented in modular form. Thus, what’s here is not fully tested, or even elegant, but there should be enough to figure out what you need to do.

Tags: api oauth ruby twitter | david | 15th Dec, 2011 at 16:32pm | No Comments

No Comments

Leave a reply

You must be logged in to post a comment.