File Coverage

lib/Net/Google/OAuth.pm
Criterion Covered Total %
statement 26 90 28.8
branch 0 12 0.0
condition 0 24 0.0
subroutine 9 17 52.9
pod 6 6 100.0
total 41 149 27.5


line stmt bran cond sub pod time code
1             package Net::Google::OAuth;
2              
3             our $VERSION = '0.03';
4              
5 1     1   2423 use 5.008001;
  1         3  
6 1     1   12 use strict;
  1         2  
  1         70  
7 1     1   13 use warnings;
  1         2  
  1         43  
8 1     1   5 use utf8;
  1         2  
  1         3  
9              
10 1     1   733 use LWP::UserAgent;
  1         51127  
  1         102  
11 1     1   8 use HTTP::Request;
  1         1  
  1         26  
12 1     1   5 use URI;
  1         2  
  1         21  
13 1     1   719 use JSON::XS;
  1         4896  
  1         63  
14 1     1   6 use Carp qw/carp croak/;
  1         19  
  1         1142  
15              
16             sub new {
17 0     0 1   my ($class, %opt) = @_;
18 0           my $self = {};
19 0   0       $self->{client_secret} = $opt{-client_secret} || croak "You must specify '-client_secret' param";
20 0   0       $self->{client_id} = $opt{-client_id} || croak "You must specify '-client_id' param";
21 0           $self->{token} = {};
22 0           $self->{ua} = LWP::UserAgent->new();
23              
24             # Get list of OpenId services
25 0           __getOpenIdServices($self);
26              
27 0           return bless $self, $class;
28             }
29              
30              
31             sub generateAccessToken {
32 0     0 1   my ($self, %opt) = @_;
33 0   0       $self->{scope} = $opt{-scope} || croak "You must specify '-scope' param";
34 0   0       $self->{email} = $opt{-email} || croak "You must specify '-email' param";
35 0           $self->{scope} = 'https://www.googleapis.com/auth/' . $self->{scope};
36              
37              
38             my $param = {
39             'client_id' => $self->{client_id},
40             'response_type' => 'code',
41             'scope' => $self->{scope},
42             'redirect_uri' => 'http://localhost:8000',
43             'state' => 'uniq_state_' . int(rand() * 100000),
44             'login_hint' => $self->{email},
45 0           'nonce' => int(rand() * 1000000) . '-' . int(rand() * 1000000) . '-' . int(rand() * 1000000),
46             'access_type' => 'offline',
47             };
48              
49 0           my $uri = URI->new($self->{services}->{authorization_endpoint});
50 0           $uri->query_form($param);
51            
52 0           print STDOUT "Please open this URL in your browser: \n", "\x1b[4;34m", $uri->as_string, "\x1b[0m", "\n";
53 0           print STDOUT "Insert redirected address from browser here:\n";
54 0           my $response_step1 = ;
55 0           $response_step1 =~ s/\r|\n//g;
56              
57 0 0         $uri = URI->new($response_step1) or croak "Can't parse response: $response_step1";
58 0           my %query_form = $uri->query_form();
59 0   0       my $code_step1 = $query_form{code} // croak "Can't get 'code' from response url";
60              
61 0           my $token = $self->__exchangeCodeToToken(
62             -code => $code_step1,
63             -grant_type => 'authorization_code',
64             );
65              
66 0           for my $key (keys %$token) {
67 0           $self->{token}->{$key} = $token->{$key};
68             }
69              
70 0           return 1;
71             }
72              
73             sub getTokenInfo {
74 0     0 1   my ($self, %opt) = @_;
75 0   0       my $access_token = $opt{-access_token} || $self->getAccessToken() || croak "You must specify '-access_token'";
76              
77 0           my $request = $self->{ua}->get('https://www.googleapis.com/oauth2/v2/tokeninfo?access_token=' . $access_token);
78 0           my $response_code = $request->code;
79 0 0         if ($response_code != 200) {
80 0           croak "Can't getTokenInfo about token: $access_token. Code: $response_code";
81             }
82              
83 0           my $response = decode_json($request->content);
84              
85 0           return $response;
86             }
87              
88              
89              
90             sub refreshToken {
91 0     0 1   my ($self, %opt) = @_;
92 0   0       my $refresh_token = $opt{-refresh_token} || croak "You must specify '-refresh_token' param";
93 0           my $token = $self->__exchangeCodeToToken(
94             -code => $refresh_token,
95             -grant_type => 'refresh_token',
96             );
97              
98 0           for my $key (keys %$token) {
99 0           $self->{token}->{$key} = $token->{$key};
100             }
101              
102 0           return 1;
103             }
104              
105             sub __exchangeCodeToToken{
106             #Exchange code or refresh token to AccessToken
107 0     0     my ($self, %opt) = @_;
108 0           my $code = $opt{-code};
109 0   0       my $grant_type = $opt{-grant_type} || croak "You must specify '-grant_type' param";
110              
111             # Exchange code to token
112             my $param = {
113             'client_id' => $self->{client_id},
114             'client_secret' => $self->{client_secret},
115 0           'redirect_uri' => 'http://localhost:8000',
116             'grant_type' => $grant_type,
117             'access_type' => 'offline',
118             };
119 0 0         if ($grant_type eq 'authorization_code') {
    0          
120 0           $param->{code} = $code;
121             }
122             elsif ($grant_type eq 'refresh_token') {
123 0           $param->{refresh_token} = $code;
124             }
125             else {
126 0           croak "Param '-grant_type' must contain values: 'authorization_code' or 'refresh_token'";
127             }
128              
129             my $response = $self->{ua}->post(
130             $self->{services}->{token_endpoint},
131 0           $param,
132             );
133 0           my $response_code = $response->code;
134 0 0         if ($response_code != 200) {
135 0           croak "Can't get token. Code: $response_code";
136             }
137              
138 0           my $token = decode_json($response->content);
139              
140 0           return $token;
141             }
142              
143             sub __getOpenIdServices {
144 0     0     my ($self) = @_;
145              
146 0           my $request = $self->{ua}->get('https://accounts.google.com/.well-known/openid-configuration');
147 0           my $response_code = $request->code;
148 0 0         if ($response_code != 200) {
149 0           croak "Can't get list of OpenId services";
150             }
151              
152 0           my $response = decode_json($request->content);
153              
154 0           $self->{services} = $response;
155              
156 0           return 1;
157             }
158              
159             ################### ACESSORS #########################
160             sub getAccessToken {
161 0     0 1   return $_[0]->{token}->{access_token};
162             }
163              
164             sub getRefreshToken {
165 0     0 1   return $_[0]->{token}->{refresh_token};
166             }
167              
168              
169             =head1 NAME
170              
171             B - Simple Google oauth api module
172              
173             =head1 SYNOPSIS
174              
175             This module get acess_token and refresh_token from google oath
176             use Net::Google::OAuth;
177              
178             #Create oauth object. You need set client_id and client_secret value. Client_id and client_secret you can get on google, when register your app.
179             my $oauth = Net::Google::OAuth->new(
180             -client_id => $CLIENT_ID,
181             -client_secret => $CLIENT_SECRET,
182             );
183             #Generate link with request access token. This link you must copy to your browser and run.
184             $oauth->generateAccessToken(
185             -scope => 'drive',
186             -email => 'youremail@gmail.com',
187             );
188             print "Access token: ", $oauth->getAccessToken(), "\n";
189             print "Refresh token: ", $oauth->getRefreshToken, "\n";
190              
191             =head1 METHODS
192              
193             =head2 new(%opt)
194              
195             Create L object
196              
197             %opt:
198             -client_id => Your app client id (Get from google when register your app)
199             -client_secret => Your app client secret (Get from google when register your app)
200              
201             =head2 generateAccessToken(%opt)
202              
203             Generate link with request access token This link you must copy to your browser and go it. Redirect answer you must copy to console. Return 1 if success, die in otherwise
204              
205             %opt
206             -scope => Request access to scope (e.g. 'drive')
207             -email => Your gmail email
208              
209             =head2 refreshToken(%opt)
210              
211             Get access token through refresh_token. Return 1 if success, die in otherwise
212              
213             %opt:
214             -refresh_token => Your refresh token value (you can get refresh token after run method generateAccessToken() via getter getRefreshToken())
215              
216             =head2 getTokenInfo(%opt)
217              
218             Get info about access token (access_type, audience, expires_in, issued_to, scope). Return hashref of result or die in otherwise
219              
220             %opt:
221             -access_token => Value of access_token (default use value returned by method getRefreshToken())
222             Example:
223             my $token_info = $oauth->getTokenInfo( -access_token => $access_token );
224             $token_info:
225             {
226             access_type "offline",
227             audience "593952972427-e6dr18ua0leurrjt1num.apps.googleusercontent.com",
228             expires_in 3558,
229             issued_to "593952972427-e6dr18ua0leurrjtum.apps.googleusercontent.com",
230             scope "https://www.googleapis.com/auth/drive"
231             }
232              
233              
234             =head2 getAccessToken()
235              
236             Return access token value
237              
238             =head2 getRefreshToken()
239              
240             Return refresh token value
241              
242             =head1 DEPENDENCE
243              
244             L, L, L, L
245              
246             =head1 AUTHORS
247              
248             =over 4
249              
250             =item *
251              
252             Pavel Andryushin
253              
254             =back
255              
256             =head1 COPYRIGHT AND LICENSE
257              
258             This software is copyright (c) 2018 by Pavel Andryushin.
259              
260             This is free software; you can redistribute it and/or modify it under
261             the same terms as the Perl 5 programming language system itself.
262              
263             =cut
264              
265             1;