I have been using the Twitter gem to post tweets regarding new blog updates. During some testing I was seeing bare passwords in urls which prompted me into migrating to using Oauth to authenticate with twitter. However this proved to be a bit of a minefield. Oauth tends to be described in explicit technical details and the gems available have cursory examples based on the simplest use cases and they never explain how to get the tokens.
So here is how to use oauth with twitter in enough detail for other people to do it. The main problem is that even if you are writing, say, a command line twitter app you will still need to write a web based app to get twitter to provide you with the right authentication keys as the process involves being redirected through the twitter web site.
First go here and ask twitter nicely for your Consumer Token and your Consumer Secret. I won't bore you with what these are, if you want to be bored read the oauth docs.
Stick these in a yaml file like this:
---
accountname:
consumer_secret: ulasdfjasdhflkshdflkjsdfhasdfasdfasdffs
consumer_token: 9asdjfhkasjdfhkhkjhkjA
I put this in RAILS_ROOT/config/twitter.yml
Now install the twitter gem:
sudm gem install twitter
Here is a library to encapsulate reading and writing these tokens. I called it PetersTwit.rb and put it in RAILS_ROOT/lib:
1
2
3
4
5 require 'rubygems'
6 require 'twitter'
7 require 'yaml'
8
9 class PetersTwit
10
11
12
13
14
15 def initialize( strConfig, strAccount)
16 @strConfig = strConfig
17 @strAccount = strAccount
18
19 @oTokens = nil
20
21 begin
22 @oAllTokens = YAML::load_file( strConfig)
23 @oTokens = @oAllTokens[@strAccount]
24 rescue
25 @oAllTokens = {}
26 end
27
28 if not @oTokens
29 @oTokens = {
30 'consumer_token' => nil,
31 'consumer_secret' => nil,
32 'access_token' => nil,
33 'access_secret' => nil,
34 }
35
36 @oAllTokens[@strAccount] = @oTokens
37 end
38 end
39
40 def consumer
41 OAuth::Consumer.new(
42 @oTokens['consumer_token'],
43 @oTokens['consumer_secret'],
44 {:site => 'http://twitter.com'}
45 )
46 end
47
48 def SetAccessToken( strToken, strSecret)
49 @oTokens['access_token'] = strToken
50 @oTokens['access_secret'] = strSecret
51 @oAllTokens[@strAccount] = @oTokens
52 Save()
53 end
54
55
56 def Save
57 YAML::dump( @oAllTokens, open( @strConfig, "w"))
58 end
59
60 def Auth
61 oAuth = Twitter::OAuth.new( @oTokens['consumer_token'], @oTokens['consumer_secret'])
62 oAuth.authorize_from_access( @oTokens['access_token'], @oTokens['access_secret'])
63
64 return oAuth
65 end
66 end
Toggle Line Numbers
Now add the following actions to a handy rails controller you may have:
1 def twitter_oauth_login
2 oTwit = PetersTwit.new( File.join( RAILS_ROOT, 'config', 'twitter.yml'), 'therealpeter')
3
4 request_token = oTwit.consumer.get_request_token
5 session[:request_token] = request_token.token
6 session[:request_token_secret] = request_token.secret
7
8 redirect_to request_token.authorize_url
9 end
10
11 def twitter_oauth_register
12 oTwit = PetersTwit.new( File.join( RAILS_ROOT, 'config', 'twitter.yml'), 'therealpeter')
13
14 request_token = OAuth::RequestToken.new( oTwit.consumer, session[:request_token], session[:request_token_secret])
15
16
17
18
19 access_token = request_token.get_access_token( :oauth_verifier => params[:oauth_verifier])
20
21 oTwit.SetAccessToken( access_token.token, access_token.secret)
22
23 redirect_to( :action => :index)
24 end
Toggle Line Numbers
When you register your application with twitter you can say it is a web application and where it asks for a callback url you can point to the url of the twitter_oauth_register. I did this but it never called me back
Run the rails app and go to the twitter_oauth_login url which should redirect you to twitter where you log into your twitter account (I'm not phishing here, honest) and authorise twitter to let your application connect to twitter without any more tedious password nonsense.
In an ideal world twitter will redirect you back to your app but this is broken for me. Instead Twitter acts as if I asked for a desktop app and displays a seven digit PIN. This can still be used by manually entering the url for:
http://yourserver/your_controller/twitter_oauth_register?oauth_verifier=1234567
where 1234567 is the PIN that twitter gave you.
After this you should have values for access_token and access_secret appear in your yaml file. These are good, keep these safe as they will let you post to twitter without passwords and crap. You can use them anywhere: web app or command line app. They allow your app to access twitter under a particular twitter user name.
Posting to twitter from the command line is now easy:
require 'PetersTwit'
require 'twitter'
oPTwit = PetersTwit.new( File.join( RAILS_ROOT, 'config', 'twitter.yml'), 'therealpeter')
oTwit = Twitter::Base.new( oPTwit.Auth())
oTwit.update( 'OMG jonas brothers')
When developing this the biggest conceptual hurdles came in the handling of the exchange of request tokens and access tokens. What can be confusing is that this can only be done once: if you get a set of request tokens you have one chance to swap them for access tokens and if you screw it up you need a fresh set of request tokens. But you don't need to know that if you follow my recipe, it's an implementation detail.