File Coverage

blib/lib/WWW/OAuth.pm
Criterion Covered Total %
statement 86 94 91.4
branch 19 36 52.7
condition 3 9 33.3
subroutine 17 19 89.4
pod 2 2 100.0
total 127 160 79.3


line stmt bran cond sub pod time code
1             package WWW::OAuth;
2              
3 1     1   192241 use strict;
  1         2  
  1         41  
4 1     1   7 use warnings;
  1         2  
  1         208  
5              
6             my %default_signer = (
7             'PLAINTEXT' => \&_signer_plaintext,
8             'HMAC-SHA1' => \&_signer_hmac_sha1,
9             );
10              
11             use Class::Tiny::Chained qw(client_id client_secret token token_secret), {
12             signature_method => 'HMAC-SHA1',
13 1         147 signer => sub { $default_signer{$_[0]->signature_method} },
14 1     1   613 };
  1         3652  
  1         14  
15              
16 1     1   1198 use Carp 'croak';
  1         3  
  1         72  
17 1     1   683 use Crypt::SysRandom 'random_bytes';
  1         4541  
  1         134  
18 1     1   9 use Digest::SHA 'hmac_sha1_base64';
  1         2  
  1         67  
19 1     1   6 use List::Util 'all', 'pairs', 'pairgrep';
  1         2  
  1         77  
20 1     1   9 use Scalar::Util 'blessed';
  1         2  
  1         47  
21 1     1   6 use URI;
  1         2  
  1         24  
22 1     1   5 use URI::Escape 'uri_escape_utf8';
  1         3  
  1         46  
23 1     1   592 use WWW::OAuth::Util 'oauth_request';
  1         4  
  1         5480  
24              
25             our $VERSION = '1.003';
26              
27             sub authenticate {
28 1     1 1 120 my $self = shift;
29 1 50       6 my @req_args = ref $_[0] ? shift() : (shift, shift);
30 1         4 my $req = oauth_request(@req_args);
31            
32 1         20 my $auth_header = $self->authorization_header($req, @_);
33            
34 1         7 $req->header(Authorization => $auth_header);
35 1         4 return $req;
36             }
37              
38             sub authorization_header {
39 2     2 1 318 my $self = shift;
40 2 50       10 my @req_args = ref $_[0] ? shift() : (shift, shift);
41 2         7 my $req = oauth_request(@req_args);
42 2         31 my $extra_params = shift;
43            
44 2         68 my ($client_id, $client_secret, $token, $token_secret, $signature_method, $signer) =
45             ($self->client_id, $self->client_secret, $self->token, $self->token_secret, $self->signature_method, $self->signer);
46            
47 2 50 33     203 croak 'Client ID and secret are required to generate authorization header'
48             unless defined $client_id and defined $client_secret;
49            
50 2 50       7 croak "Signer is required for signature method $signature_method" unless defined $signer;
51            
52 2 50 33     9 if ($signature_method eq 'RSA-SHA1' and blessed $signer) {
53 0         0 my $signer_obj = $signer;
54 0 0       0 croak 'Signer for RSA-SHA1 must have "sign" method' unless $signer_obj->can('sign');
55 0     0   0 $signer = sub { $signer_obj->sign($_[0]) };
  0         0  
56             }
57 2 50 33     16 croak "Signer for $signature_method must be a coderef" unless !blessed $signer and ref $signer eq 'CODE';
58            
59 2         9 my %oauth_params = (
60             oauth_consumer_key => $client_id,
61             oauth_nonce => _nonce(),
62             oauth_signature_method => $signature_method,
63             oauth_timestamp => time,
64             oauth_version => '1.0',
65             );
66 2 100       9 $oauth_params{oauth_token} = $token if defined $token;
67            
68             # Extra parameters passed to authenticate()
69 2 50       7 if (defined $extra_params) {
70 2 50       6 croak 'OAuth parameters must be specified as a hashref' unless ref $extra_params eq 'HASH';
71             croak 'OAuth parameters other than "realm" must all begin with "oauth_"'
72 2 100   2   21 unless all { $_ eq 'realm' or m/^oauth_/ } keys %$extra_params;
  2 50       15  
73 2         20 %oauth_params = (%oauth_params, %$extra_params);
74             }
75            
76             # This parameter is not allowed when creating the signature
77 2         6 delete $oauth_params{oauth_signature};
78            
79             # Don't bother to generate signature base string for PLAINTEXT method
80 2 50       13 my $base_str = $signature_method eq 'PLAINTEXT' ? '' : _signature_base_string($req, \%oauth_params);
81 2         324 $oauth_params{oauth_signature} = $signer->($base_str, $client_secret, $token_secret);
82            
83 2         28 my $auth_str = join ', ', map { $_ . '="' . uri_escape_utf8($oauth_params{$_}) . '"' } sort keys %oauth_params;
  15         336  
84 2         58 return "OAuth $auth_str";
85             }
86              
87 2     2   42 sub _nonce { scalar unpack 'H*', random_bytes(20) } # random hex string
88              
89             sub _signer_plaintext {
90 0     0   0 my ($base_str, $client_secret, $token_secret) = @_;
91 0 0       0 $token_secret = '' unless defined $token_secret;
92 0         0 return uri_escape_utf8($client_secret) . '&' . uri_escape_utf8($token_secret);
93             }
94              
95             sub _signer_hmac_sha1 {
96 2     2   7 my ($base_str, $client_secret, $token_secret) = @_;
97 2 100       8 $token_secret = '' unless defined $token_secret;
98 2         8 my $signing_key = uri_escape_utf8($client_secret) . '&' . uri_escape_utf8($token_secret);
99 2         134 my $digest = hmac_sha1_base64($base_str, $signing_key);
100 2 50       14 $digest .= '='x(4 - length($digest) % 4) if length($digest) % 4; # Digest::SHA does not pad Base64 digests
101 2         8 return $digest;
102             }
103              
104             sub _signature_base_string {
105 2     2   5 my ($req, $oauth_params) = @_;
106            
107 2         4 my @all_params = @{$req->query_pairs};
  2         14  
108 2         13432 push @all_params, map { ($_ => $oauth_params->{$_}) } grep { $_ ne 'realm' } keys %$oauth_params;
  12         62  
  13         26  
109 2 50       12 push @all_params, @{$req->body_pairs} if $req->content_is_form;
  0         0  
110 2         6 my @pairs = pairs map { uri_escape_utf8 $_ } @all_params;
  24         451  
111 2 50       96 @pairs = sort { ($a->[0] cmp $b->[0]) or ($a->[1] cmp $b->[1]) } @pairs;
  21         61  
112 2         5 my $params_str = join '&', map { $_->[0] . '=' . $_->[1] } @pairs;
  12         35  
113            
114 2         67 my $base_url = URI->new($req->url);
115 2         211 $base_url->query(undef);
116 2         51 $base_url->fragment(undef);
117 2         88 return uc($req->method) . '&' . uri_escape_utf8($base_url) . '&' . uri_escape_utf8($params_str);
118             }
119              
120             1;
121              
122             =head1 NAME
123              
124             WWW::OAuth - Portable OAuth 1.0 authentication
125              
126             =head1 SYNOPSIS
127              
128             use WWW::OAuth;
129            
130             my $oauth = WWW::OAuth->new(
131             client_id => $client_id,
132             client_secret => $client_secret,
133             token => $token,
134             token_secret => $token_secret,
135             );
136            
137             # Just retrieve authorization header
138             my $auth_header = $oauth->authorization_header($http_request, { oauth_callback => $url });
139             $http_request->header(Authorization => $auth_header);
140            
141             # HTTP::Tiny
142             use HTTP::Tiny;
143             my $res = $oauth->authenticate(Basic => { method => 'GET', url => $url })
144             ->request_with(HTTP::Tiny->new);
145            
146             # HTTP::Request
147             use HTTP::Request::Common;
148             use LWP::UserAgent;
149             my $res = $oauth->authenticate(GET $url)->request_with(LWP::UserAgent->new);
150            
151             # Mojo::Message::Request
152             use Mojo::UserAgent;
153             my $tx = $ua->build_tx(get => $url);
154             $tx = $oauth->authenticate($tx->req)->request_with(Mojo::UserAgent->new);
155            
156             =head1 DESCRIPTION
157              
158             L implements OAuth 1.0 request authentication according to
159             L (sometimes referred to as OAuth
160             1.0A). It does not implement the user agent requests needed for the complete
161             OAuth 1.0 authorization flow; it only prepares and signs requests, leaving the
162             rest up to your application. It can authenticate requests for
163             L, L, L, and can be extended to
164             operate on other types of requests.
165              
166             Some user agents can be configured to automatically authenticate each request
167             with a L object.
168              
169             # LWP::UserAgent
170             my $ua = LWP::UserAgent->new;
171             $ua->add_handler(request_prepare => sub { $oauth->authenticate($_[0]) });
172            
173             # Mojo::UserAgent
174             my $ua = Mojo::UserAgent->new;
175             $ua->on(start => sub { $oauth->authenticate($_[1]->req) });
176              
177             =head1 RETRIEVING ACCESS TOKENS
178              
179             The process of retrieving access tokens and token secrets for authorization on
180             behalf of a user may differ among various APIs, but it follows this general
181             format (error checking is left as an exercise to the reader):
182              
183             use WWW::OAuth;
184             use WWW::OAuth::Util 'form_urldecode';
185             use HTTP::Tiny;
186             my $ua = HTTP::Tiny->new;
187             my $oauth = WWW::OAuth->new(
188             client_id => $client_id,
189             client_secret => $client_secret,
190             );
191            
192             # Request token request
193             my $res = $oauth->authenticate({ method => 'POST', url => $request_token_url },
194             { oauth_callback => $callback_url })->request_with($ua);
195             my %res_data = @{form_urldecode $res->{content}};
196             my ($request_token, $request_secret) = @res_data{'oauth_token','oauth_token_secret'};
197            
198             Now, the returned request token must be used to construct a URL for the user to
199             go to and authorize your application. The exact method differs by API. The user
200             will usually be redirected to the C<$callback_url> passed earlier after
201             authorizing, with a verifier token that can be used to retrieve the access
202             token and secret.
203            
204             # Access token request
205             $oauth->token($request_token);
206             $oauth->token_secret($request_secret);
207             my $res = $oauth->authenticate({ method => 'POST', url => $access_token_url },
208             { oauth_verifier => $verifier_token })->request_with($ua);
209             my %res_data = @{form_urldecode $res->{content}};
210             my ($access_token, $access_secret) = @res_data{'oauth_token','oauth_token_secret'};
211            
212             Finally, the access token and secret can now be stored and used to authorize
213             your application on behalf of this user.
214              
215             $oauth->token($access_token);
216             $oauth->token_secret($access_secret);
217              
218             =head1 ATTRIBUTES
219              
220             L implements the following attributes.
221              
222             =head2 client_id
223              
224             my $client_id = $oauth->client_id;
225             $oauth = $oauth->client_id($client_id);
226              
227             Client ID used to identify application (sometimes called an API key or consumer
228             key). Required for all requests.
229              
230             =head2 client_secret
231              
232             my $client_secret = $oauth->client_secret;
233             $oauth = $oauth->client_secret($client_secret);
234              
235             Client secret used to authenticate application (sometimes called an API secret
236             or consumer secret). Required for all requests.
237              
238             =head2 token
239              
240             my $token = $oauth->token;
241             $oauth = $oauth->token($token);
242              
243             Request or access token used to identify resource owner. Leave undefined for
244             temporary credentials requests (request token requests).
245              
246             =head2 token_secret
247              
248             my $token_secret = $oauth->token_secret;
249             $oauth = $oauth->token_secret($token_secret);
250              
251             Request or access token secret used to authenticate on behalf of resource
252             owner. Leave undefined for temporary credentials requests (request token
253             requests).
254              
255             =head2 signature_method
256              
257             my $method = $oauth->signature_method;
258             $oauth = $oauth->signature_method($method);
259              
260             Signature method, can be C, C<HMAC-SHA1>, C<RSA-SHA1>, or a custom </td> </tr> <tr> <td class="h" > <a name="261">261</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> signature method. For C<RSA-SHA1> or custom signature methods, a L</"signer"> </td> </tr> <tr> <td class="h" > <a name="262">262</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> must be provided. Defaults to C<HMAC-SHA1>. </td> </tr> <tr> <td class="h" > <a name="263">263</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> &nbsp; </td> </tr> <tr> <td class="h" > <a name="264">264</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> =head2 signer </td> </tr> <tr> <td class="h" > <a name="265">265</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> &nbsp; </td> </tr> <tr> <td class="h" > <a name="266">266</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> my $signer = $oauth->signer; </td> </tr> <tr> <td class="h" > <a name="267">267</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> $oauth = $oauth->signer(sub { </td> </tr> <tr> <td class="h" > <a name="268">268</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> my ($base_str, $client_secret, $token_secret) = @_; </td> </tr> <tr> <td class="h" > <a name="269">269</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> ... </td> </tr> <tr> <td class="h" > <a name="270">270</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> return $signature; </td> </tr> <tr> <td class="h" > <a name="271">271</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> }); </td> </tr> <tr> <td class="h" > <a name="272">272</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> &nbsp; </td> </tr> <tr> <td class="h" > <a name="273">273</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> Coderef which implements the L</"signature_method">. A default signer is </td> </tr> <tr> <td class="h" > <a name="274">274</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> provided for signature methods C<PLAINTEXT> and C<HMAC-SHA1>; this attribute is </td> </tr> <tr> <td class="h" > <a name="275">275</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> required for other signature methods. For signature method C<RSA-SHA1>, this </td> </tr> <tr> <td class="h" > <a name="276">276</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> attribute may also be an object which has a C<sign> method like </td> </tr> <tr> <td class="h" > <a name="277">277</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> L<Crypt::OpenSSL::RSA>. </td> </tr> <tr> <td class="h" > <a name="278">278</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> &nbsp; </td> </tr> <tr> <td class="h" > <a name="279">279</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> The signer is passed the computed signature base string, the client secret, and </td> </tr> <tr> <td class="h" > <a name="280">280</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> (if present) the token secret, and must return the signature string. </td> </tr> <tr> <td class="h" > <a name="281">281</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> &nbsp; </td> </tr> <tr> <td class="h" > <a name="282">282</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> =head1 METHODS </td> </tr> <tr> <td class="h" > <a name="283">283</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> &nbsp; </td> </tr> <tr> <td class="h" > <a name="284">284</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> L<WWW::OAuth> implements the following methods. </td> </tr> <tr> <td class="h" > <a name="285">285</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> &nbsp; </td> </tr> <tr> <td class="h" > <a name="286">286</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> =head2 authenticate </td> </tr> <tr> <td class="h" > <a name="287">287</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> &nbsp; </td> </tr> <tr> <td class="h" > <a name="288">288</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> $container = $oauth->authenticate($container, \%oauth_params); </td> </tr> <tr> <td class="h" > <a name="289">289</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> my $container = $oauth->authenticate($http_request, \%oauth_params); </td> </tr> <tr> <td class="h" > <a name="290">290</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> my $container = $oauth->authenticate(Basic => { method => 'GET', url => $url }, \%oauth_params); </td> </tr> <tr> <td class="h" > <a name="291">291</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> &nbsp; </td> </tr> <tr> <td class="h" > <a name="292">292</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> Wraps the HTTP request in a container with L<WWW::OAuth::Util/"oauth_request">, </td> </tr> <tr> <td class="h" > <a name="293">293</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> then sets the Authorization header using L</"authorization_header"> to sign the </td> </tr> <tr> <td class="h" > <a name="294">294</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> request for OAuth 1.0. An optional hashref of OAuth parameters will be passed </td> </tr> <tr> <td class="h" > <a name="295">295</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> through to L</"authorization_header">. Returns the container object. </td> </tr> <tr> <td class="h" > <a name="296">296</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> &nbsp; </td> </tr> <tr> <td class="h" > <a name="297">297</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> =head2 authorization_header </td> </tr> <tr> <td class="h" > <a name="298">298</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> &nbsp; </td> </tr> <tr> <td class="h" > <a name="299">299</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> my $auth_header = $oauth->authorization_header($container, \%oauth_params); </td> </tr> <tr> <td class="h" > <a name="300">300</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> my $auth_header = $oauth->authorization_header($http_request, \%oauth_params); </td> </tr> <tr> <td class="h" > <a name="301">301</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> my $auth_header = $oauth->authorization_header(Basic => { method => 'GET', url => $url }, \%oauth_params); </td> </tr> <tr> <td class="h" > <a name="302">302</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> &nbsp; </td> </tr> <tr> <td class="h" > <a name="303">303</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> Forms an OAuth 1.0 signed Authorization header for the passed request. As in </td> </tr> <tr> <td class="h" > <a name="304">304</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> L</"authenticate">, the request may be specified in any form accepted by </td> </tr> <tr> <td class="h" > <a name="305">305</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> L<WWW::OAuth::Util/"oauth_request">. OAuth protocol parameters (starting with </td> </tr> <tr> <td class="h" > <a name="306">306</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> C<oauth_> or the special parameter C<realm>) may be optionally specified in a </td> </tr> <tr> <td class="h" > <a name="307">307</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> hashref and will override any generated protocol parameters of the same name </td> </tr> <tr> <td class="h" > <a name="308">308</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> (they should not be present in the request URL or body parameters). Returns the </td> </tr> <tr> <td class="h" > <a name="309">309</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> signed header value. </td> </tr> <tr> <td class="h" > <a name="310">310</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> &nbsp; </td> </tr> <tr> <td class="h" > <a name="311">311</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> =head1 HTTP REQUEST CONTAINERS </td> </tr> <tr> <td class="h" > <a name="312">312</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> &nbsp; </td> </tr> <tr> <td class="h" > <a name="313">313</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> Request containers provide a unified interface for L</"authenticate"> to parse </td> </tr> <tr> <td class="h" > <a name="314">314</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> and update HTTP requests. They must perform the L<Role::Tiny> role </td> </tr> <tr> <td class="h" > <a name="315">315</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> L<WWW::OAuth::Request>. Custom container classes can be instantiated </td> </tr> <tr> <td class="h" > <a name="316">316</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> directly or via L<WWW::OAuth::Util/"oauth_request">. </td> </tr> <tr> <td class="h" > <a name="317">317</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> &nbsp; </td> </tr> <tr> <td class="h" > <a name="318">318</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> =head2 Basic </td> </tr> <tr> <td class="h" > <a name="319">319</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> &nbsp; </td> </tr> <tr> <td class="h" > <a name="320">320</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> L<WWW::OAuth::Request::Basic> contains the request attributes directly, for </td> </tr> <tr> <td class="h" > <a name="321">321</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> user agents such as L<HTTP::Tiny> that do not use request objects. </td> </tr> <tr> <td class="h" > <a name="322">322</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> &nbsp; </td> </tr> <tr> <td class="h" > <a name="323">323</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> =head2 HTTP_Request </td> </tr> <tr> <td class="h" > <a name="324">324</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> &nbsp; </td> </tr> <tr> <td class="h" > <a name="325">325</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> L<WWW::OAuth::Request::HTTP_Request> wraps a L<HTTP::Request> object, which </td> </tr> <tr> <td class="h" > <a name="326">326</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> is compatible with several user agents including L<LWP::UserAgent>, </td> </tr> <tr> <td class="h" > <a name="327">327</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> L<HTTP::Thin>, and L<Net::Async::HTTP>. </td> </tr> <tr> <td class="h" > <a name="328">328</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> &nbsp; </td> </tr> <tr> <td class="h" > <a name="329">329</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> =head2 Mojo </td> </tr> <tr> <td class="h" > <a name="330">330</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> &nbsp; </td> </tr> <tr> <td class="h" > <a name="331">331</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> L<WWW::OAuth::Request::Mojo> wraps a L<Mojo::Message::Request> object, </td> </tr> <tr> <td class="h" > <a name="332">332</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> which is used by L<Mojo::UserAgent> via L<Mojo::Transaction>. </td> </tr> <tr> <td class="h" > <a name="333">333</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> &nbsp; </td> </tr> <tr> <td class="h" > <a name="334">334</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> =head1 BUGS </td> </tr> <tr> <td class="h" > <a name="335">335</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> &nbsp; </td> </tr> <tr> <td class="h" > <a name="336">336</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> Report any issues on the public bugtracker. </td> </tr> <tr> <td class="h" > <a name="337">337</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> &nbsp; </td> </tr> <tr> <td class="h" > <a name="338">338</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> This module was developed primarily to interface with the Twitter API, which is </td> </tr> <tr> <td class="h" > <a name="339">339</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> now functionally unusable, so further development of this module is unlikely </td> </tr> <tr> <td class="h" > <a name="340">340</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> without another use case. </td> </tr> <tr> <td class="h" > <a name="341">341</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> &nbsp; </td> </tr> <tr> <td class="h" > <a name="342">342</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> =head1 AUTHOR </td> </tr> <tr> <td class="h" > <a name="343">343</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> &nbsp; </td> </tr> <tr> <td class="h" > <a name="344">344</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> Dan Book <dbook@cpan.org> </td> </tr> <tr> <td class="h" > <a name="345">345</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> &nbsp; </td> </tr> <tr> <td class="h" > <a name="346">346</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> =head1 COPYRIGHT AND LICENSE </td> </tr> <tr> <td class="h" > <a name="347">347</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> &nbsp; </td> </tr> <tr> <td class="h" > <a name="348">348</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> This software is Copyright (c) 2015 by Dan Book. </td> </tr> <tr> <td class="h" > <a name="349">349</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> &nbsp; </td> </tr> <tr> <td class="h" > <a name="350">350</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> This is free software, licensed under: </td> </tr> <tr> <td class="h" > <a name="351">351</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> &nbsp; </td> </tr> <tr> <td class="h" > <a name="352">352</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> The Artistic License 2.0 (GPL Compatible) </td> </tr> <tr> <td class="h" > <a name="353">353</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> &nbsp; </td> </tr> <tr> <td class="h" > <a name="354">354</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> =head1 SEE ALSO </td> </tr> <tr> <td class="h" > <a name="355">355</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> &nbsp; </td> </tr> <tr> <td class="h" > <a name="356">356</a> </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td > &nbsp; </td> <td class="s"> L<Net::OAuth>, L<Mojolicious::Plugin::OAuth2> </td> </tr> </table> </body> </html>