+ my $host = shift;
+
+ die "PayPal client ID (username) must be configured\n"
+ unless $self->username;
+ die "PayPay client secret (password) must be configured\n"
+ unless $self->password;
+
+ $self->{cache} = Cache::FileCache->new(
+ { cache_root => File::Spec->tmpdir,
+ namespace => 'BOTP-PayPal' }
+ );
+ $self->{cipher} = Crypt::CBC->new( -key => $self->password,
+ -cipher => 'Blowfish' );
+
+ if ( my $token = $self->cache->get($self->username) ) {
+ $self->access_token( $self->cipher->decrypt($token) );
+ } else {
+ my $ua = LWP::UserAgent->new;
+ my $auth_request = HTTP::Request->new(POST => "$host/v1/oauth2/token");
+ $auth_request->header('Accept' => 'application/json');
+ # documentation says application/json; it lies.
+ $auth_request->header('Content-Type'=>
+ 'application/x-www-form-urlencoded');
+ $auth_request->authorization_basic( $self->username, $self->password );
+ $auth_request->content('grant_type=client_credentials');
+ warn "Sending authentication request.\n" if $DEBUG;
+ my $auth_response = $ua->request($auth_request);
+ unless ( $auth_response->is_success ) {
+ die "Authentication failed: ".$auth_response->status_line."\n".
+ $auth_response->content;
+ }
+ warn "Authentication response:\n".$auth_response->content."\n\n"
+ if $DEBUG > 2;
+ my $hash = decode_json($auth_response->content);
+ my $token = $hash->{access_token};
+ $self->access_token($token);
+ $self->cache->set($self->username, $self->cipher->encrypt( $token ),
+ $hash->{expires_in} - 5);
+ }
+ return $self->access_token;