File Coverage

blib/lib/WWW/OAuth.pm
Criterion Covered Total %
statement 80 88 90.9
branch 18 34 52.9
condition 3 9 33.3
subroutine 16 18 88.8
pod 2 2 100.0
total 119 151 78.8


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