Twitter opened up their OAuth implementation last week. It's a much welcome aspect of working with Twitter's API since we're planning on implementing some functionality into Semblr that uses Twitter. Hence, understanding OAuth and prototyping it's use was important for us.
My problem with Twitter's implementation is that the documentation is sparse and there isn't a single example in Perl or Java. Maybe these two languages aren't cool enough to warrant examples but to me, they're important because they're all I know. I spent some time over the last few days trying to implement OAuth for Twitter in my Perl scripts. The example below is a bit messy but it works.
It will create a few temp files, request a token for you, ask you to go to the URL printed to authorize the application. When you've authorized the application, run the script again and it will allow you to submit a status update.
#! /usr/local/bin/perl # $Author: pankaj $ # $Date: 2009-03-22 23:46:27 +0530 (Sun, 22 Mar 2009) $ # Author: Pankaj Jain # Copyright: Teknatus Solutions LLC ################################################################################################################################ use Modern::Perl; use Carp; use Net::OAuth; use Data::Random qw(rand_chars); use LWP::UserAgent; use Data::Dumper; use JSON::Any; main(); sub main{ my $ua = LWP::UserAgent->new; my $consumer_key = 'sdBwlvTkpZr7eiCmB0Evig'; my $consumer_secret = 'asSINZmwnxwIfLwmdNvVBW7OSVzFOWj4mjJeDDaA'; my %tokens = getTokens(); requestToken(consumer_key => $consumer_key, consumer_secret => $consumer_secret, %tokens, ua => $ua); my $message = "This is a Perl Net::OAuth test for twitter!"; my $foo = {status => $message}; my $url = 'https://twitter.com/statuses/update.json'; if (defined $message && $message ne "") { my $request = Net::OAuth->request("protected resource")->new( consumer_key => $consumer_key, consumer_secret => $consumer_secret, request_url => $url, request_method => 'POST', signature_method => 'HMAC-SHA1', timestamp => time, nonce => join('', rand_chars(size=>16, set=>'alphanumeric')), token => $tokens{token}, token_secret => $tokens{secret}, extra_params => $foo, ); $request->sign; say Dumper($request); my $response = $ua->post($request->to_url); say Dumper($response); my $response_code = $response->code; my $response_message = $response->message; my $response_error = $response->content; if ($response->is_success) { my $retval = eval { JSON::Any->jsonToObj( $response->content ) }; if ( !defined $retval ) { say "TWITTER RETURNED SUCCESS BUT PARSING OF THE RESPONSE FAILED - " . $response->content; } } else { say $response_code; } exit; } } sub requestToken { my %args = @_; if (defined $args{consumer_key} && defined $args{consumer_secret} && !defined $args{access_token} && !defined $args{access_secret} && !defined $args{token} && !defined $args{token_secret}) { my $token; my $secret; my $request = Net::OAuth->request("consumer")->new( consumer_key => $args{consumer_key}, consumer_secret => $args{consumer_secret}, request_url => 'https://twitter.com/oauth/request_token', request_method => 'GET', signature_method => 'HMAC-SHA1', timestamp => time, nonce => join('', rand_chars(size=>16, set=>'alphanumeric')) ); $request->sign; my $res = $args{ua}->get($request->to_url); # Post message to the Service Provider if ($res->is_success) { my $response = Net::OAuth->response('request token')->from_post_body($res->content); print "Got Request Token ", $response->token, "\n"; $token = $response->token; print "Got Request Token Secret ", $response->token_secret, "\n"; $secret = $response->token_secret; if (defined $token) { my $auth_url = "https://twitter.com/oauth/authorize?oauth_token=" . $token; my $message = "Please visit $auth_url and authorize this application to access your twitter account. You may revoke access at any time you wish.\n"; say $message . "\n"; open(TMP,">/tmp/request_token.txt"); say TMP $token . "|" . $secret; close TMP; exit; } } else { die "Something went wrong"; } } elsif (defined $args{access_token} && defined $args{access_secret} && defined $args{consumer_key} && defined $args{consumer_secret} && !defined $args{token} && !defined $args{token_secret}) { my $auth_req = Net::OAuth->request("access token")->new( consumer_key => $args{consumer_key}, consumer_secret => $args{consumer_secret}, token => $args{access_token}, token_secret => $args{access_secret}, request_url => 'http://twitter.com/oauth/access_token', request_method => 'POST', signature_method => 'HMAC-SHA1', timestamp => time, nonce => join('', rand_chars(size=>16, set=>'alphanumeric')) ); $auth_req->sign(); my $res2 = $args{ua}->post($auth_req->to_url); # Post message to the Service Provider if (!$res2->is_success) { die 'Could not get an Access Token: ' . $res2->status_line . ' ' . $res2->content; } else { open(TF, ">$ENV{HOME}/.teknatus/.twitter_token"); my $response = Net::OAuth->response('access token')->from_post_body($res2->content); print STDERR "Got Access Token ", $response->token, "\n"; my $access_tok = $response->token; print STDERR "Got Access Token Secret ", $response->token_secret, "\n"; my $access_secret = $response->token_secret; say TF $access_tok . "|" .$access_secret; close TF; unlink("/tmp/request_token.txt") if (-e "/tmp/request_token.txt"); } exit; } } sub getTokens { my %args = @_; my %tokens; my $tokenFile = $ENV{HOME} ."/.teknatus/.twitter_token"; my $reqTokenFile = "/tmp/request_token.txt"; if (-e $tokenFile ) { open (TF, "<$tokenFile"); while() { chop($_); next if ( $_ =~ /^\s?$/); my @tmp = split(/\|/, $_); $tokens{token} = $tmp[0]; $tokens{secret} = $tmp[1]; } close TF; } if (-e $reqTokenFile) { open (TF, "<$reqTokenFile"); while( ) { chop($_); next if ( $_ =~ /^\s?$/); my @tmp = split(/\|/, $_); $tokens{access_token} = $tmp[0]; $tokens{access_secret} = $tmp[1]; } close TF; } return %tokens; } 1;
$ENV{"HOME"}
Hi Pankaj
First off, thanks for posting this info.
Basicaly being a non programmer, (but familiar with the basics of perl scripting), this post is very useful.
I am not sure that I am missing the obvious but when I try to run the script via a browser I get the following error returned in my apache error log:
Use of uninitialized value $ENV{"HOME"} in concatenation (.) or string at twitteroauth.cgi line 137.
Something went wrong at twitteroauth.cgi line 99.
line 137 being
my $tokenFile = $ENV{HOME} ."/.teknatus/.twitter_token";
Any help much appreciated,
Thanks
Caitanya Candra das
For the Comman Line
Caitanya,
The script above is not for a browser. To make a a browser script, you would have to make some changes and implement CGI, mod_perl, Catalyst or some other Web framework within the script. This script is meant to be run from the command line. You will need to make sure you have all the modules installed to be able to run it.
When you run it from the command line, your token to access Twitter will be saved in $ENV{HOME}/.teknatus/.twitter_token, e.g. /home/caitanya/.teknatus/.twitter_token - so that it can be accessed easily on subsequent runs of the script.
I hope that helps.
Cheers,
Pankaj