Twitter Opens up OAuth, Where’s Perl?

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;

Related Posts:

4 Replies to “Twitter Opens up OAuth, Where’s Perl?”

  1. Pankaj,
    Thanks so much for your reply.
    Have been looking high and low to find a solution where i can pass my message variable to a subroutine to send tweets via oauth on a web project I am working on…. but despite a lot of time wasted searching, it seems, at least for Perl, there are no working examples.
    Your script, as you mentioned needs to be adapted to work via a browser, or even better as a subroutine for a web application – considering there is nothing out there, ior at best incomlete solutions, and that you have laid the ground work, could you knock up an adaption, say using CGI?
    In that way a lot more people can benefit from your coding. 🙂
    Thanks
    Caitanya

  2. Caitanya,

    The code above is meant as an example of what can be done with Perl. If you require our services in making a Perl based Web application to interface with Twitter, then we can definitely speak about the project and what the scope of work would be.

    Cheers,
    Pankaj

Comments are closed.