File Coverage

blib/lib/OAuth/Lite2/Client/WebServer.pm
Criterion Covered Total %
statement 40 42 95.2
branch n/a
condition n/a
subroutine 14 14 100.0
pod n/a
total 54 56 96.4


line stmt bran cond sub pod time code
1             package OAuth::Lite2::Client::WebServer;
2              
3 1     1   5 use strict;
  1         2  
  1         32  
4 1     1   4 use warnings;
  1         2  
  1         31  
5              
6 1     1   5 use base 'Class::ErrorHandler';
  1         2  
  1         719  
7              
8 1     1   213 use Params::Validate qw(HASHREF);
  1         2  
  1         53  
9 1     1   5 use Carp ();
  1         2  
  1         17  
10 1     1   7 use bytes ();
  1         2  
  1         20  
11 1     1   6 use URI;
  1         1  
  1         17  
12 1     1   3 use LWP::UserAgent;
  1         2  
  1         15  
13 1     1   8 use HTTP::Request;
  1         1  
  1         16  
14 1     1   4 use HTTP::Headers;
  1         1  
  1         15  
15 1     1   3 use Try::Tiny;
  1         1  
  1         39  
16              
17 1     1   4 use OAuth::Lite2;
  1         1  
  1         24  
18 1     1   4 use OAuth::Lite2::Util qw(build_content);
  1         1  
  1         31  
19 1     1   35 use OAuth::Lite2::Formatters;
  0            
  0            
20             use OAuth::Lite2::Client::TokenResponseParser;
21              
22             =head1 NAME
23              
24             OAuth::Lite2::Client::WebServer - OAuth 2.0 Web Server Profile Client
25              
26             =head1 SYNOPSIS
27              
28             my $client = OAuth::Lite2::Client::WebServer->new(
29             id => q{my_client_id},
30             secret => q{my_client_secret},
31             authorize_uri => q{http://example.org/authorize},
32             access_token_uri => q{http://example.org/token},
33             );
34              
35             # redirect user to authorize page.
36             sub start_authorize {
37             my $your_app = shift;
38             my $redirect_url = $client->uri_to_redirect(
39             redirect_uri => q{http://yourapp/callback},
40             scope => q{photo},
41             state => q{optional_state},
42             );
43              
44             $your_app->res->redirect( $redirect_url );
45             }
46              
47             # this method corresponds to the url 'http://yourapp/callback'
48             sub callback {
49             my $your_app = shift;
50              
51             my $code = $your_app->request->param("code");
52              
53             my $access_token = $client->get_access_token(
54             code => $code,
55             redirect_uri => q{http://yourapp/callback},
56             ) or return $your_app->error( $client->errstr );
57              
58             $your_app->store->save( access_token => $access_token->access_token );
59             $your_app->store->save( expires_at => time() + $access_token->expires_in );
60             $your_app->store->save( refresh_token => $access_token->refresh_token );
61             }
62              
63             sub refresh_access_token {
64             my $your_app = shift;
65              
66             my $access_token = $client->refresh_access_token(
67             refresh_token => $refresh_token,
68             ) or return $your_app->error( $client->errstr );
69              
70             $your_app->store->save( access_token => $access_token->access_token );
71             $your_app->store->save( expires_at => time() + $access_token->expires_in );
72             $your_app->store->save( refresh_token => $access_token->refresh_token );
73             }
74              
75              
76             sub access_to_protected_resource {
77             my $your_app = shift;
78              
79             my $access_token = $your_app->store->get("access_token");
80             my $expires_at = $your_app->store->get("expires_at");
81             my $refresh_token = $your_app->store->get("refresh_token");
82              
83             unless ($access_token) {
84             $your_app->start_authorize();
85             return;
86             }
87              
88             if ($expires_at < time()) {
89             $your_app->refresh_access_token();
90             return;
91             }
92              
93             my $req = HTTP::Request->new( GET => q{http://example.org/photo} );
94             $req->header( Authorization => sprintf(q{OAuth %s}, $access_token) );
95             my $agent = LWP::UserAgent->new;
96             my $res = $agent->request($req);
97             ...
98             }
99              
100              
101             =head1 DESCRIPTION
102              
103             Client library for OAuth 2.0 Web Server Profile.
104              
105             =head1 METHODS
106              
107             =head2 new( %params )
108              
109             =over 4
110              
111             =item id
112              
113             Client ID
114              
115             =item secret
116              
117             Client secret
118              
119             =item authorize_uri
120              
121             authorization page uri on auth-server.
122              
123             =item access_token_uri
124              
125             token endpoint uri on auth-server.
126              
127             =item refresh_token_uri
128              
129             refresh-token endpoint uri on auth-server.
130             if you omit this, access_token_uri is used instead.
131              
132             =item agent
133              
134             user agent. if you omit this, LWP::UserAgent's object is set by default.
135             You can use your custom agent or preset-agents.
136              
137             See also
138              
139             L
140             L
141             L
142              
143             =back
144              
145             =cut
146              
147             sub new {
148              
149             my $class = shift;
150              
151             my %args = Params::Validate::validate(@_, {
152             id => 1,
153             secret => 1,
154             # format => { optional => 1 },
155             authorize_uri => { optional => 1 },
156             access_token_uri => { optional => 1 },
157             refresh_token_uri => { optional => 1 },
158             agent => { optional => 1 },
159             });
160              
161             my $self = bless {
162             id => undef,
163             secret => undef,
164             authorize_uri => undef,
165             access_token_uri => undef,
166             refresh_token_uri => undef,
167             last_request => undef,
168             last_response => undef,
169             %args,
170             }, $class;
171              
172             unless ($self->{agent}) {
173             $self->{agent} = LWP::UserAgent->new;
174             $self->{agent}->agent(
175             join "/", __PACKAGE__, $OAuth::Lite2::VERSION);
176             }
177              
178             $self->{format} ||= 'json';
179             $self->{response_parser} = OAuth::Lite2::Client::TokenResponseParser->new;
180              
181             return $self;
182             }
183              
184             =head2 uri_to_redirect( %params )
185              
186             =cut
187              
188             sub uri_to_redirect {
189             my $self = shift;
190             my %args = Params::Validate::validate(@_, {
191             redirect_uri => 1,
192             state => { optional => 1 },
193             scope => { optional => 1 },
194             immediate => { optional => 1 },
195             uri => { optional => 1 },
196             extra => { optional => 1, type => HASHREF },
197             });
198              
199             my %params = (
200             response_type => 'code',
201             client_id => $self->{id},
202             redirect_uri => $args{redirect_uri},
203             );
204             $params{state} = $args{state} if $args{state};
205             $params{scope} = $args{scope} if $args{scope};
206             $params{immediate} = $args{immediate} if $args{immediate};
207              
208             if ($args{extra}) {
209             for my $key ( keys %{$args{extra}} ) {
210             $params{$key} = $args{extra}{$key};
211             }
212             }
213              
214             my $uri = $args{uri}
215             || $self->{authorize_uri}
216             || Carp::croak "uri not found";
217              
218             $uri = URI->new($uri);
219             $uri->query_form(%params);
220             return $uri->as_string;
221             }
222              
223             =head2 get_access_token( %params )
224              
225             execute verification,
226             and returns L object.
227              
228             =over 4
229              
230             =item code
231              
232             Authorization-code that is issued beforehand by server
233              
234             =item redirect_uri
235              
236             The URL that has used for user authorization's callback
237              
238             =back
239              
240             =cut
241              
242             sub get_access_token {
243             my $self = shift;
244              
245             my %args = Params::Validate::validate(@_, {
246             code => 1,
247             redirect_uri => 1,
248             uri => { optional => 1 },
249             # secret_type => { optional => 1 },
250             # format => { optional => 1 },
251             });
252              
253             unless (exists $args{uri}) {
254             $args{uri} = $self->{access_token_uri}
255             || Carp::croak "uri not found";
256             }
257              
258             # $args{format} ||= $self->{format};
259              
260             my %params = (
261             grant_type => 'authorization_code',
262             client_id => $self->{id},
263             client_secret => $self->{secret},
264             code => $args{code},
265             redirect_uri => $args{redirect_uri},
266             # format => $args{format},
267             );
268              
269             # $params{secret_type} = $args{secret_type}
270             # if $args{secret_type};
271              
272             my $content = build_content(\%params);
273             my $headers = HTTP::Headers->new;
274             $headers->header("Content-Type" => q{application/x-www-form-urlencoded});
275             $headers->header("Content-Length" => bytes::length($content));
276             my $req = HTTP::Request->new( POST => $args{uri}, $headers, $content );
277              
278             my $res = $self->{agent}->request($req);
279             $self->{last_request} = $req;
280             $self->{last_response} = $res;
281              
282             my ($token, $errmsg);
283             try {
284             $token = $self->{response_parser}->parse($res);
285             } catch {
286             $errmsg = "$_";
287             };
288             return $token || $self->error($errmsg);
289             }
290              
291             =head2 refresh_access_token( %params )
292              
293             Refresh access token by refresh_token,
294             returns L object.
295              
296             =over 4
297              
298             =item refresh_token
299              
300             =back
301              
302             =cut
303              
304             sub refresh_access_token {
305             my $self = shift;
306              
307             my %args = Params::Validate::validate(@_, {
308             refresh_token => 1,
309             # secret_type => { optional => 1 },
310             # format => { optional => 1 },
311             uri => { optional => 1 },
312             });
313              
314             unless (exists $args{uri}) {
315             $args{uri} = $self->{access_token_uri}
316             || Carp::croak "uri not found";
317             }
318              
319             # $args{format} ||= $self->{format};
320              
321             my %params = (
322             grant_type => 'refresh_token',
323             client_id => $self->{id},
324             client_secret => $self->{secret},
325             refresh_token => $args{refresh_token},
326             # format => $args{format},
327             );
328              
329             # $params{secret_type} = $args{secret_type}
330             # if $args{secret_type};
331              
332             my $content = build_content(\%params);
333             my $headers = HTTP::Headers->new;
334             $headers->header("Content-Type" => q{application/x-www-form-urlencoded});
335             $headers->header("Content-Length" => bytes::length($content));
336             my $req = HTTP::Request->new( POST => $args{uri}, $headers, $content );
337              
338             my $res = $self->{agent}->request($req);
339             $self->{last_request} = $req;
340             $self->{last_response} = $res;
341              
342             my ($token, $errmsg);
343             try {
344             $token = $self->{response_parser}->parse($res);
345             } catch {
346             $errmsg = "$_";
347             };
348             return $token || $self->error($errmsg);
349              
350             }
351              
352             =head2 last_request
353              
354             Returns a HTTP::Request object that is used
355             when you obtain or refresh access token last time internally.
356              
357             =head2 last_request
358              
359             Returns a HTTP::Response object that is used
360             when you obtain or refresh access token last time internally.
361              
362             =cut
363              
364             sub last_request { $_[0]->{last_request} }
365             sub last_response { $_[0]->{last_response} }
366              
367             =head1 AUTHOR
368              
369             Lyo Kato, Elyo.kato@gmail.comE
370              
371             =head1 COPYRIGHT AND LICENSE
372              
373             Copyright (C) 2010 by Lyo Kato
374              
375             This library is free software; you can redistribute it and/or modify
376             it under the same terms as Perl itself, either Perl version 5.8.8 or,
377             at your option, any later version of Perl 5 you may have available.
378              
379             =cut
380              
381             1;