File Coverage

blib/lib/Net/OAuth/Simple.pm
Criterion Covered Total %
statement 41 225 18.2
branch 3 72 4.1
condition 3 24 12.5
subroutine 12 49 24.4
pod 29 29 100.0
total 88 399 22.0


line stmt bran cond sub pod time code
1             package Net::OAuth::Simple;
2              
3 2     2   175886 use warnings;
  2         6  
  2         73  
4 2     2   11 use strict;
  2         3  
  2         105  
5             our $VERSION = "1.5";
6              
7 2     2   1220 use URI;
  2         14208  
  2         61  
8 2     2   938 use LWP;
  2         71277  
  2         124  
9 2     2   6046 use CGI;
  2         37529  
  2         25  
10 2     2   2281 use HTTP::Request::Common ();
  2         4682  
  2         43  
11 2     2   15 use Carp;
  2         5  
  2         155  
12 2     2   2428 use Net::OAuth;
  2         1693  
  2         72  
13 2     2   15 use Scalar::Util qw(blessed);
  2         6  
  2         351  
14             require Net::OAuth::Request;
15             require Net::OAuth::RequestTokenRequest;
16             require Net::OAuth::AccessTokenRequest;
17             require Net::OAuth::ProtectedResourceRequest;
18             require Net::OAuth::XauthAccessTokenRequest;
19              
20             BEGIN {
21 2     2   14 eval { require Math::Random::MT };
  2         940  
22 2 50       6724 unless ($@) {
23 0         0 Math::Random::MT->import(qw(srand rand));
24             }
25             }
26              
27             our @required_constructor_params = qw(consumer_key consumer_secret);
28             our @access_token_params = qw(access_token access_token_secret);
29             our @general_token_params = qw(general_token general_token_secret);
30             our $UNAUTHORIZED = "Unauthorized.";
31              
32             =head1 NAME
33              
34             Net::OAuth::Simple - a simple wrapper round the OAuth protocol
35              
36             =head1 SYNOPSIS
37              
38             First create a sub class of C that will do you requests
39             for you.
40              
41             package Net::AppThatUsesOAuth;
42              
43             use strict;
44             use base qw(Net::OAuth::Simple);
45              
46              
47             sub new {
48             my $class = shift;
49             my %tokens = @_;
50             return $class->SUPER::new( tokens => \%tokens,
51             protocol_version => '1.0a',
52             urls => {
53             authorization_url => ...,
54             request_token_url => ...,
55             access_token_url => ...,
56             });
57             }
58              
59             sub view_restricted_resource {
60             my $self = shift;
61             my $url = shift;
62             return $self->make_restricted_request($url, 'GET');
63             }
64              
65             sub update_restricted_resource {
66             my $self = shift;
67             my $url = shift;
68             my %extra_params = @_;
69             return $self->make_restricted_request($url, 'POST', %extra_params);
70             }
71             1;
72              
73              
74             Then in your main app you need to do
75              
76             # Get the tokens from the command line, a config file or wherever
77             my %tokens = get_tokens();
78             my $app = Net::AppThatUsesOAuth->new(%tokens);
79              
80             # Check to see we have a consumer key and secret
81             unless ($app->consumer_key && $app->consumer_secret) {
82             die "You must go get a consumer key and secret from App\n";
83             }
84            
85             # If the app is authorized (i.e has an access token and secret)
86             # Then look at a restricted resourse
87             if ($app->authorized) {
88             my $response = $app->view_restricted_resource;
89             print $response->content."\n";
90             exit;
91             }
92              
93              
94             # Otherwise the user needs to go get an access token and secret
95             print "Go to ".$app->get_authorization_url."\n";
96             print "Then hit return after\n";
97             ;
98              
99             my ($access_token, $access_token_secret) = $app->request_access_token;
100              
101             # Now save those values
102              
103              
104             Note the flow will be somewhat different for web apps since the request token
105             and secret will need to be saved whilst the user visits the authorization url.
106              
107             For examples go look at the C module and the C command
108             line script that ships with it. Also in the same distribution in the C
109             directory is a sample web app.
110              
111             =head1 METHODS
112              
113             =cut
114              
115             =head2 new [params]
116              
117             Create a new OAuth enabled app - takes a hash of params.
118              
119             One of the keys of the hash must be C, the value of which
120             must be a hash ref with the keys:
121              
122             =over 4
123              
124             =item consumer_key
125              
126             =item consumer_secret
127              
128             =back
129              
130             Then, when you have your per-use access token and secret you
131             can supply
132              
133             =over 4
134              
135             =item access_token
136              
137             =item access_secret
138              
139             =back
140              
141             Another key of the hash must be C, the value of which must
142             be a hash ref with the keys
143              
144             =over 4
145              
146             =item authorization_url
147              
148             =item request_token_url
149              
150             =item access_token_url
151              
152             =back
153              
154             If you pass in a key C with a value equal to B<1.0a> then
155             the newest version of the OAuth protocol will be used. A value equal to B<1.0> will
156             mean the old version will be used. Defaults to B<1.0a>
157              
158             You can pass in your own User Agent by using the key C.
159              
160             If you pass in C then instead of C-ing on error
161             methods will return undef instead and the error can be retrieved using the
162             C method. See the section on B.
163              
164             =cut
165              
166             sub new {
167 1     1 1 3732 my $class = shift;
168 1         6 my %params = @_;
169 1   50     11 $params{protocol_version} ||= '1.0a';
170 1         4 my $client = bless \%params, $class;
171            
172             # Set up LibWWWPerl for HTTP requests
173 1   33     12 $client->{browser} ||= LWP::UserAgent->new;
174              
175             # Verify arguments
176 1         6 $client->_check;
177              
178            
179              
180             # Client Object
181 1         4 return $client;
182             }
183              
184             # Validate required constructor params
185             sub _check {
186 1     1   3 my $self = shift;
187              
188 1         5 foreach my $param ( @required_constructor_params ) {
189 2 50       13 unless ( defined $self->{tokens}->{$param} ) {
190 0         0 return $self->_error("Missing required parameter '$param'");
191             }
192             }
193            
194 1 50 33     25 return $self->_error("browser must be a LWP::UserAgent")
195             unless blessed $self->{browser} && $self->{browser}->isa('LWP::UserAgent');
196             }
197              
198             =head2 oauth_1_0a
199              
200             Whether or not we're using 1.0a version of OAuth (necessary for,
201             amongst others, FireEagle)
202              
203             =cut
204             sub oauth_1_0a {
205 0     0 1   my $self = shift;
206 0           return $self->{protocol_version } eq '1.0a';
207             }
208              
209             =head2 authorized
210              
211             Whether the client has the necessary credentials to be authorized.
212              
213             Note that the credentials may be wrong and so the request may still fail.
214              
215             =cut
216              
217             sub authorized {
218 0     0 1   my $self = shift;
219 0           foreach my $param ( @access_token_params ) {
220 0 0 0       return 0 unless defined $self->{tokens}->{$param} && length $self->{tokens}->{$param};
221             }
222 0           return 1;
223             }
224              
225             =head2 signature_method [method]
226              
227             The signature method to use.
228              
229             Defaults to HMAC-SHA1
230              
231             =cut
232             sub signature_method {
233 0     0 1   my $self = shift;
234 0 0         $self->{signature_method} = shift if @_;
235 0   0       return $self->{signature_method} || 'HMAC-SHA1';
236             }
237              
238             =head2 tokens
239              
240             Get all the tokens.
241              
242             =cut
243             sub tokens {
244 0     0 1   my $self = shift;
245 0 0         if (@_) {
246 0           my %tokens = @_;
247 0           $self->{tokens} = \%tokens;
248             }
249 0 0         return %{$self->{tokens}||{}};
  0            
250             }
251              
252             =head2 consumer_key [consumer key]
253              
254             Returns the current consumer key.
255              
256             Can optionally set the consumer key.
257              
258             =cut
259              
260             sub consumer_key {
261 0     0 1   my $self = shift;
262 0           $self->_token('consumer_key', @_);
263             }
264              
265             =head2 consumer_secret [consumer secret]
266              
267             Returns the current consumer secret.
268              
269             Can optionally set the consumer secret.
270              
271             =cut
272              
273             sub consumer_secret {
274 0     0 1   my $self = shift;
275 0           $self->_token('consumer_secret', @_);
276             }
277              
278              
279             =head2 access_token [access_token]
280              
281             Returns the current access token.
282              
283             Can optionally set a new token.
284              
285             =cut
286              
287             sub access_token {
288 0     0 1   my $self = shift;
289 0           $self->_token('access_token', @_);
290             }
291              
292             =head2 access_token_secret [access_token_secret]
293              
294             Returns the current access token secret.
295              
296             Can optionally set a new secret.
297              
298             =cut
299              
300             sub access_token_secret {
301 0     0 1   my $self = shift;
302 0           return $self->_token('access_token_secret', @_);
303             }
304              
305             =head2 general_token [token]
306              
307             Get or set the general token.
308              
309             See documentation in C
310              
311             =cut
312              
313             sub general_token {
314 0     0 1   my $self = shift;
315 0           $self->_token('general_token', @_);
316             }
317              
318             =head2 general_token_secret [secret]
319              
320             Get or set the general token secret.
321              
322             See documentation in C
323              
324             =cut
325              
326             sub general_token_secret {
327 0     0 1   my $self = shift;
328 0           $self->_token('general_token_secret', @_);
329             }
330              
331             =head2 authorized_general_token
332              
333             Is the app currently authorized for general token requests.
334              
335             See documentation in C
336              
337             =cut
338              
339             sub authorized_general_token {
340 0     0 1   my $self = shift;
341 0           foreach my $param ( @general_token_params ) {
342 0 0         return 0 unless defined $self->$param();
343             }
344 0           return 1;
345             }
346              
347              
348             =head2 request_token [request_token]
349              
350             Returns the current request token.
351              
352             Can optionally set a new token.
353              
354             =cut
355              
356             sub request_token {
357 0     0 1   my $self = shift;
358 0           $self->_token('request_token', @_);
359             }
360              
361              
362             =head2 request_token_secret [request_token_secret]
363              
364             Returns the current request token secret.
365              
366             Can optionally set a new secret.
367              
368             =cut
369              
370             sub request_token_secret {
371 0     0 1   my $self = shift;
372 0           return $self->_token('request_token_secret', @_);
373             }
374              
375             =head2 verifier [verifier]
376              
377             Returns the current oauth_verifier.
378              
379             Can optionally set a new verifier.
380              
381             =cut
382              
383             sub verifier {
384 0     0 1   my $self = shift;
385 0           return $self->_param('verifier', @_);
386             }
387              
388             =head2 callback [callback]
389              
390             Returns the oauth callback.
391              
392             Can optionally set the oauth callback.
393              
394             =cut
395              
396             sub callback {
397 0     0 1   my $self = shift;
398 0           $self->_param('callback', @_);
399             }
400              
401             =head2 callback_confirmed [callback_confirmed]
402              
403             Returns the oauth callback confirmed.
404              
405             Can optionally set the oauth callback confirmed.
406              
407             =cut
408              
409             sub callback_confirmed {
410 0     0 1   my $self = shift;
411 0           $self->_param('callback_confirmed', @_);
412             }
413              
414              
415             sub _token {
416 0     0     my $self = shift;
417 0           $self->_store('tokens', @_);
418             }
419              
420             sub _param {
421 0     0     my $self = shift;
422 0           $self->_store('params', @_);
423             }
424              
425             sub _store {
426 0     0     my $self = shift;
427 0           my $ns = shift;
428 0           my $key = shift;
429 0 0         $self->{$ns}->{$key} = shift if @_;
430 0           return $self->{$ns}->{$key};
431             }
432              
433             =head2 authorization_url
434              
435             Get the url the user needs to visit to authorize as a URI object.
436              
437             Note: this is the base url - not the full url with the necessary OAuth params.
438              
439             =cut
440             sub authorization_url {
441 0     0 1   my $self = shift;
442 0           return $self->_url('authorization_url', @_);
443             }
444              
445              
446             =head2 request_token_url
447              
448             Get the url to obtain a request token as a URI object.
449              
450             =cut
451             sub request_token_url {
452 0     0 1   my $self = shift;
453 0           return $self->_url('request_token_url', @_);
454             }
455              
456             =head2 access_token_url
457              
458             Get the url to obtain an access token as a URI object.
459              
460             =cut
461             sub access_token_url {
462 0     0 1   my $self = shift;
463 0           return $self->_url('access_token_url', @_);
464             }
465              
466             sub _url {
467 0     0     my $self = shift;
468 0           my $key = shift;
469 0 0         $self->{urls}->{$key} = shift if @_;
470 0   0       my $url = $self->{urls}->{$key} || return;;
471 0           return URI->new($url);
472             }
473              
474             # generate a random number
475             sub _nonce {
476 0     0     return int( rand( 2**32 ) );
477             }
478              
479             =head2 request_access_token [param[s]]
480              
481             Request the access token and access token secret for this user.
482              
483             The user must have authorized this app at the url given by
484             C first.
485              
486             Returns the access token and access token secret but also sets
487             them internally so that after calling this method you can
488             immediately call a restricted method.
489              
490             If you pass in a hash of params then they will added as parameters to the URL.
491              
492             =cut
493              
494             sub request_access_token {
495 0     0 1   my $self = shift;
496 0           my %params = @_;
497 0           my $url = $self->access_token_url;
498            
499 0 0         $params{token} = $self->request_token unless defined $params{token};
500 0 0         $params{token_secret} = $self->request_token_secret unless defined $params{token_secret};
501            
502 0 0         if ($self->oauth_1_0a) {
503 0 0         $params{verifier} = $self->verifier unless defined $params{verifier};
504 0 0         return $self->_error("You must pass a verified parameter when using OAuth v1.0a") unless defined $params{verifier};
505            
506             }
507            
508            
509 0           my $access_token_response = $self->_make_request(
510             'Net::OAuth::AccessTokenRequest',
511             $url, 'GET',
512             %params,
513             );
514              
515 0           return $self->_decode_tokens($url, $access_token_response);
516             }
517              
518             sub _decode_tokens {
519 0     0     my $self = shift;
520 0           my $url = shift;
521 0           my $access_token_response = shift;
522              
523             # Cast response into CGI query for EZ parameter decoding
524 0           my $access_token_response_query =
525             new CGI( $access_token_response->content );
526              
527             # Split out token and secret parameters from the access token response
528 0           $self->access_token($access_token_response_query->param('oauth_token'));
529 0           $self->access_token_secret($access_token_response_query->param('oauth_token_secret'));
530              
531 0           delete $self->{tokens}->{$_} for qw(request_token request_token_secret verifier);
532              
533 0 0 0       return $self->_error("ERROR: $url did not reply with an access token")
534             unless ( $self->access_token && $self->access_token_secret );
535              
536 0           return ( $self->access_token, $self->access_token_secret );
537            
538             }
539              
540             =head2 xauth_request_access_token [param[s]]
541              
542             The same as C but for xAuth.
543              
544             For more information on xAuth see
545              
546             http://apiwiki.twitter.com/Twitter-REST-API-Method%3A-oauth-access_token-for-xAuth
547              
548             You must pass in the parameters
549              
550             x_auth_username
551             x_auth_password
552             x_auth_mode
553              
554             You must have HTTPS enabled for LWP::UserAgent.
555              
556             See C for a sample implementation.
557              
558             =cut
559             sub xauth_request_access_token {
560 0     0 1   my $self = shift;
561 0           my %params = @_;
562 0           my $url = $self->access_token_url;
563 0           $url =~ s !^http:!https:!; # force https
564              
565 0           my %xauth_params = map { $_ => $params{$_} }
  0            
566 0           grep {/^x_auth_/}
567 0           @{Net::OAuth::XauthAccessTokenRequest->required_message_params};
568              
569 0           my $access_token_response = $self->_make_request(
570             'Net::OAuth::XauthAccessTokenRequest',
571             $url, 'POST',
572             %xauth_params,
573             );
574              
575 0           return $self->_decode_tokens($url, $access_token_response);
576             }
577              
578             =head2 request_request_token [param[s]]
579              
580             Request the request token and request token secret for this user.
581              
582             This is called automatically by C if necessary.
583              
584             If you pass in a hash of params then they will added as parameters to the URL.
585              
586             =cut
587              
588              
589             sub request_request_token {
590 0     0 1   my $self = shift;
591 0           my %params = @_;
592 0           my $url = $self->request_token_url;
593            
594 0 0         if ($self->oauth_1_0a) {
595 0 0         $params{callback} = $self->callback unless defined $params{callback};
596 0 0         return $self->_error("You must pass a callback parameter when using OAuth v1.0a") unless defined $params{callback};
597             }
598            
599 0           my $request_token_response = $self->_make_request(
600             'Net::OAuth::RequestTokenRequest',
601             $url, 'GET',
602             %params);
603              
604 0 0         return $self->_error("GET for $url failed: ".$request_token_response->status_line)
605             unless ( $request_token_response->is_success );
606              
607             # Cast response into CGI query for EZ parameter decoding
608 0           my $request_token_response_query =
609             new CGI( $request_token_response->content );
610              
611             # Split out token and secret parameters from the request token response
612 0           $self->request_token($request_token_response_query->param('oauth_token'));
613 0           $self->request_token_secret($request_token_response_query->param('oauth_token_secret'));
614 0           $self->callback_confirmed($request_token_response_query->param('oauth_callback_confirmed'));
615            
616 0 0 0       return $self->_error("Response does not confirm to OAuth1.0a. oauth_callback_confirmed not received")
617             if $self->oauth_1_0a && !$self->callback_confirmed;
618              
619             }
620              
621             =head2 get_authorization_url [param[s]]
622              
623             Get the URL to authorize a user as a URI object.
624              
625             If you pass in a hash of params then they will added as parameters to the URL.
626              
627             =cut
628              
629             sub get_authorization_url {
630 0     0 1   my $self = shift;
631 0           my %params = @_;
632 0           my $url = $self->authorization_url;
633 0 0         if (!defined $self->request_token) {
634 0           $self->request_request_token(%params);
635             }
636 0           $params{oauth_token} = $self->request_token;
637 0           $url->query_form(%params);
638 0           return $url;
639             }
640              
641             =head2 make_restricted_request [extra[s]]
642              
643             Make a request to C using the given HTTP method.
644              
645             Any extra parameters can be passed in as a hash.
646              
647             =cut
648             sub make_restricted_request {
649 0     0 1   my $self = shift;
650              
651 0 0         return $self->_error($UNAUTHORIZED) unless $self->authorized;
652              
653 0           return $self->_restricted_request( $self->access_token, $self->access_token_secret, @_ );
654             }
655              
656             =head2 make_general_request [extra[s]]
657              
658             Make a request to C using the given HTTP method using
659             the general purpose tokens.
660              
661             Any extra parameters can be passed in as a hash.
662              
663             =cut
664             sub make_general_request {
665 0     0 1   my $self = shift;
666              
667 0 0         croak $UNAUTHORIZED unless $self->authorized_general_token;
668              
669 0           return $self->_restricted_request( $self->general_token, $self->general_token_secret, @_ );
670             }
671              
672             sub _restricted_request {
673 0     0     my $self = shift;
674 0           my $token = shift;
675 0           my $secret = shift;
676 0           my $url = shift;
677 0           my $method = shift;
678 0           my %extras = @_;
679 0           my $response = $self->_make_request(
680             'Net::OAuth::ProtectedResourceRequest',
681             $url, $method,
682             token => $token,
683             token_secret => $secret,
684             extra_params => \%extras
685             );
686 0           return $response;
687             }
688              
689             sub _make_request {
690 0     0     my $self = shift;
691 0           my $class = shift;
692 0           my $url = shift;
693 0           my $method = uc(shift);
694 0           my @extra = @_;
695              
696 0           my $uri = URI->new($url);
697 0           my %query = $uri->query_form;
698 0           $uri->query_form({});
699            
700 0 0         my $request = $class->new(
701             consumer_key => $self->consumer_key,
702             consumer_secret => $self->consumer_secret,
703             request_url => $uri,
704             request_method => $method,
705             signature_method => $self->signature_method,
706             protocol_version => $self->oauth_1_0a ? Net::OAuth::PROTOCOL_VERSION_1_0A : Net::OAuth::PROTOCOL_VERSION_1_0,
707             timestamp => time,
708             nonce => $self->_nonce,
709             extra_params => \%query,
710             @extra,
711             );
712 0           $request->sign;
713 0 0         return $self->_error("COULDN'T VERIFY! Check OAuth parameters.")
714             unless $request->verify;
715              
716 0           my @args = ();
717 0           my $req_url = $url;
718 0           my $params = $request->to_hash;
719 0 0 0       if ('GET' eq $method || 'PUT' eq $method) {
720 0           $req_url = URI->new($url);
721 0           $req_url->query_form(%$params);
722             } else {
723 0           @args = ( HTTP::Headers->new(%$params) );
724             }
725            
726 0           my $req = HTTP::Request->new( $method => $req_url, @args);
727 0           my $response = $self->{browser}->request($req);
728 0 0         return $self->_error("$method on $request failed: ".$response->status_line)
729             unless ( $response->is_success );
730              
731 0           return $response;
732             }
733              
734             sub _error {
735 0     0     my $self = shift;
736 0           my $mess = shift;
737 0 0         if ($self->{return_undef_on_error}) {
738 0           $self->{_last_error} = $mess;
739             } else {
740 0           croak $mess;
741             }
742 0           return undef;
743             }
744              
745             =head2 last_error
746              
747             Get the last error message.
748              
749             Only works if C was passed in to the constructor.
750              
751             See the section on B.
752              
753             =cut
754             sub last_error {
755 0     0 1   my $self = shift;
756 0           return $self->{_last_error};
757             }
758              
759             =head2 load_tokens
760              
761             A convenience method for loading tokens from a config file.
762              
763             Returns a hash with the token names suitable for passing to
764             C.
765              
766             Returns an empty hash if the file doesn't exist.
767              
768             =cut
769             sub load_tokens {
770 0     0 1   my $class = shift;
771 0           my $file = shift;
772 0           my %tokens = ();
773 0 0         return %tokens unless -f $file;
774              
775 0 0         open(my $fh, $file) || die "Couldn't open $file: $!\n";
776 0           while (<$fh>) {
777 0           chomp;
778 0 0         next if /^#/;
779 0 0         next if /^\s*$/;
780 0 0         next unless /=/;
781 0           s/(^\s*|\s*$)//g;
782 0           my ($key, $val) = split /\s*=\s*/, $_, 2;
783 0           $tokens{$key} = $val;
784             }
785 0           close($fh);
786 0           return %tokens;
787             }
788              
789             =head2 save_tokens [token[s]]
790              
791             A convenience method to save a hash of tokens out to the given file.
792              
793             =cut
794             sub save_tokens {
795 0     0 1   my $class = shift;
796 0           my $file = shift;
797 0           my %tokens = @_;
798              
799 0           my $max = 0;
800 0           foreach my $key (keys %tokens) {
801 0 0         $max = length($key) if length($key)>$max;
802             }
803              
804 0 0         open(my $fh, ">$file") || die "Couldn't open $file for writing: $!\n";
805 0           foreach my $key (sort keys %tokens) {
806 0           my $pad = " "x($max-length($key));
807 0           print $fh "$key ${pad}= ".$tokens{$key}."\n";
808             }
809 0           close($fh);
810             }
811              
812             =head1 ERROR HANDLING
813              
814             Originally this module would die upon encountering an error (inheriting behaviour
815             from the original Yahoo! code).
816              
817             This is still the default behaviour however if you now pass
818              
819             return_undef_on_error => 1
820            
821             into the constructor then all methods will return undef on error instead.
822              
823             The error message is accessible via the C method.
824              
825             =head1 GOOGLE'S SCOPE PARAMETER
826              
827             Google's OAuth API requires the non-standard C parameter to be set
828             in C, and you also explicitly need to pass an C
829             to C method, so that you can direct the user to your site
830             if you're authenticating users in Web Application mode. Otherwise Google will let
831             user grant acesss as a desktop app mode and doesn't redirect users back.
832              
833             Here's an example class that uses Google's Portable Contacts API via OAuth:
834              
835             package Net::AppUsingGoogleOAuth;
836             use strict;
837             use base qw(Net::OAuth::Simple);
838              
839             sub new {
840             my $class = shift;
841             my %tokens = @_;
842             return $class->SUPER::new(
843             tokens => \%tokens,
844             urls => {
845             request_token_url => "https://www.google.com/accounts/OAuthGetRequestToken?scope=http://www-opensocial.googleusercontent.com/api/people",
846             authorization_url => "https://www.google.com/accounts/OAuthAuthorizeToken",
847             access_token_url => "https://www.google.com/accounts/OAuthGetAccessToken",
848             },
849             );
850             }
851              
852             package main;
853             my $oauth = Net::AppUsingGoogleOAuth->new(%tokens);
854              
855             # Web application
856             $app->redirect( $oauth->get_authorization_url( callback => "http://you.example.com/oauth/callback") );
857              
858             # Desktop application
859             print "Open the URL and come back once you're authenticated!\n",
860             $oauth->get_authorization_url;
861              
862             See L and other
863             services API documentation for the possible list of I parameter value.
864              
865             =head1 RANDOMNESS
866              
867             If C is installed then any nonces generated will use a
868             Mersenne Twiser instead of Perl's built in randomness function.
869              
870             =head1 EXAMPLES
871              
872             There are example Twitter and Twitter xAuth 'desktop' apps and a FireEagle OAuth 1.0a web app
873             in the examples directory of the distribution.
874              
875             =head1 BUGS
876              
877             Non known
878              
879             =head1 DEVELOPERS
880              
881             The latest code for this module can be found at
882              
883             https://svn.unixbeard.net/simon/Net-OAuth-Simple
884              
885             =head1 AUTHOR
886              
887             Simon Wistow, C<>
888              
889             =head1 BUGS
890              
891             Please report any bugs or feature requests to C, or through
892             the web interface at L. I will be notified, and then you'll
893             automatically be notified of progress on your bug as I make changes.
894              
895             =head1 SUPPORT
896              
897             You can find documentation for this module with the perldoc command.
898              
899             perldoc Net::OAuth::Simple
900              
901              
902             You can also look for information at:
903              
904             =over 4
905              
906             =item * RT: CPAN's request tracker
907              
908             L
909              
910             =item * AnnoCPAN: Annotated CPAN documentation
911              
912             L
913              
914             =item * CPAN Ratings
915              
916             L
917              
918             =item * Search CPAN
919              
920             L
921              
922             =back
923              
924             =head1 COPYRIGHT & LICENSE
925              
926             Copyright 2009 Simon Wistow, all rights reserved.
927              
928             This program is free software; you can redistribute it and/or modify it
929             under the same terms as Perl itself.
930              
931              
932             =cut
933              
934             1; # End of Net::OAuth::Simple