File Coverage

blib/lib/Amazon/CreatorsAPI/Auth.pm
Criterion Covered Total %
statement 30 58 51.7
branch 4 16 25.0
condition 5 22 22.7
subroutine 9 13 69.2
pod 2 2 100.0
total 50 111 45.0


line stmt bran cond sub pod time code
1             package Amazon::CreatorsAPI::Auth;
2 2     2   12 use strict;
  2         5  
  2         73  
3 2     2   10 use warnings;
  2         4  
  2         165  
4 2     2   11 use Carp qw/croak/;
  2         3  
  2         124  
5 2     2   10 use JSON qw//;
  2         4  
  2         31  
6 2     2   8 use HTTP::Tiny;
  2         6  
  2         82  
7 2     2   1005 use WWW::Form::UrlEncoded qw/build_urlencoded/;
  2         10958  
  2         202  
8             use Class::Accessor::Lite (
9 2         21 ro => [qw/
10             credential_id
11             credential_secret
12             credential_version
13             is_lwa
14             auth_endpoint
15             ua
16             grant_type
17             /],
18             rw => [qw/
19             access_token
20             expires_at
21             /],
22 2     2   1055 );
  2         3046  
23              
24             our $JSON = JSON->new;
25              
26             sub new {
27 1     1 1 2 my $class = shift;
28 1 50       4 my $credential_id = shift or croak 'credential_id is required';
29 1 50       2 my $credential_secret = shift or croak 'credential_secret is required';
30 1 50       3 my $credential_version = shift or croak 'credential_version is required';
31 1   50     3 my $opt = shift || +{};
32              
33             return bless +{
34             credential_id => $credential_id,
35             credential_secret => $credential_secret,
36             credential_version => $credential_version,
37             is_lwa => !!($credential_version =~ m!^3\.!),
38             auth_endpoint => $opt->{auth_endpoint} || _auth_endpoint($credential_version),
39             ua => $opt->{ua} || HTTP::Tiny->new,
40 1   33     9 grant_type => $opt->{grant_type} || 'client_credentials',
      33        
      50        
41             access_token => '',
42             expires_at => 0,
43             }, $class;
44             }
45              
46             sub get_access_token {
47 0     0 1 0 my $self = shift;
48              
49 0 0       0 if ($self->_is_valid_token) {
50 0         0 return $self->access_token;
51             }
52              
53 0         0 return $self->_refresh_token;
54             }
55              
56             sub _is_valid_token {
57 0     0   0 my $self = shift;
58              
59 0   0     0 return $self->access_token && $self->expires_at && time() < $self->expires_at;
60             }
61              
62             sub _refresh_token {
63 0     0   0 my $self = shift;
64              
65 0         0 my $res;
66 0 0       0 if ($self->is_lwa) {
67 0         0 $res = $self->ua->request(
68             'POST',
69             $self->auth_endpoint,
70             {
71             'headers' => {
72             'Content-Type' => 'application/json',
73             },
74             'content' => $JSON->encode({
75             'grant_type' => $self->grant_type,
76             'client_id' => $self->credential_id,
77             'client_secret' => $self->credential_secret,
78             'scope' => 'creatorsapi::default',
79             }),
80             },
81             );
82             }
83             else {
84 0         0 $res = $self->ua->request(
85             'POST',
86             $self->auth_endpoint,
87             {
88             'headers' => {
89             'Content-Type' => 'application/x-www-form-urlencoded',
90             },
91             'content' => build_urlencoded(
92             'grant_type' => $self->grant_type,
93             'client_id' => $self->credential_id,
94             'client_secret' => $self->credential_secret,
95             'scope' => 'creatorsapi/default',
96             ),
97             },
98             );
99             }
100              
101 0 0       0 if (!$res->{success}) {
102 0         0 $self->_clear_token;
103             croak "failed to get token status:$res->{status} "
104 0   0     0 . ($res->{reason} || 'reason_unknown')
105             . ", $res->{content}";
106             }
107              
108 0         0 my $res_data = +{};
109 0         0 eval {
110 0         0 $res_data = $JSON->decode($res->{content});
111             };
112 0 0       0 if (my $e = $@) {
113 0         0 $self->_clear_token;
114 0         0 croak "could not JSON decode, $e : " . $res->{content};
115             }
116              
117 0   0     0 $self->expires_at(time() + ($res_data->{expires_in} || 3600) - 30);
118 0         0 $self->access_token($res_data->{access_token});
119              
120 0         0 return $self->access_token;
121             }
122              
123             my $AUTH_ENDPOINT_MAP = {
124             '2.1' => 'https://creatorsapi.auth.us-east-1.amazoncognito.com/oauth2/token',
125             '2.2' => 'https://creatorsapi.auth.eu-south-2.amazoncognito.com/oauth2/token',
126             '2.3' => 'https://creatorsapi.auth.us-west-2.amazoncognito.com/oauth2/token',
127             '3.1' => 'https://api.amazon.com/auth/o2/token',
128             '3.2' => 'https://api.amazon.co.uk/auth/o2/token',
129             '3.3' => 'https://api.amazon.co.jp/auth/o2/token',
130             };
131              
132             sub _auth_endpoint {
133 1     1   2 my $version = shift;
134              
135 1 50 33     7 if (!$version || !exists $AUTH_ENDPOINT_MAP->{$version}) {
136             croak "Unsupported version: "
137             . ($version || 'unknown')
138 0   0     0 . ", Supported: " . join(", ", sort keys %{$AUTH_ENDPOINT_MAP});
  0         0  
139             }
140              
141 1         34 return $AUTH_ENDPOINT_MAP->{$version};
142             }
143              
144             sub _clear_token {
145 0     0     my $self = shift;
146              
147 0           $self->access_token(undef);
148 0           $self->expires_at(undef);
149             }
150              
151             1;
152              
153             __END__