package Twitter::API::Trait::AppAuth;
# ABSTRACT: App-only (OAuth2) Authentication
$Twitter::API::Trait::AppAuth::VERSION = '1.0006';
use Moo::Role;
use Carp;
use URL::Encode qw/url_encode url_decode/;
use namespace::clean;
requires qw/
_url_for access_token add_authorization api_url consumer_key
consumer_secret request
/;
# private methods
sub oauth2_url_for {
my $self = shift;
$self->_url_for('', $self->api_url, 'oauth2', @_);
}
my $add_consumer_auth_header = sub {
my ( $self, $req ) = @_;
$req->headers->authorization_basic(
$self->consumer_key, $self->consumer_secret);
};
# public methods
#pod =method oauth2_token
#pod
#pod Call the C<oauth2/token> endpoint to get a bearer token. The token is not
#pod stored in Twitter::API's state. If you want that, set the C<access_token>
#pod attribute with the returned token.
#pod
#pod See L<https://developer.twitter.com/en/docs/basics/authentication/api-reference/token> for details.
#pod
#pod =cut
sub oauth2_token {
my $self = shift;
my ( $r, $c ) = $self->request(post => $self->oauth2_url_for('token'), {
-add_consumer_auth_header => 1,
grant_type => 'client_credentials',
});
# In their wisdom, Twitter sends us a URL encoded token. We need to decode
# it, so if/when we call invalidate_token, and properly URL encode our
# parameters, we don't end up with a double-encoded token.
my $token = url_decode $$r{access_token};
return wantarray ? ( $token, $c ) : $token;
}
#pod =method invalidate_token($token)
#pod
#pod Calls the C<oauth2/invalidate_token> endpoint to revoke a token. See
#pod L<https://developer.twitter.com/en/docs/basics/authentication/api-reference/invalidate_token> for
#pod details.
#pod
#pod =cut
sub invalidate_token {
my ( $self, $token ) = @_;
my ( $r, $c ) = $self->request(
post =>$self->oauth2_url_for('invalidate_token'), {
-add_consumer_auth_header => 1,
access_token => $token,
});
my $token_returned = url_decode $$r{access_token};
return wantarray ? ( $token_returned, $c ) : $token_returned;
}
# request chain modifiers
around add_authorization => sub {
shift; # we're overriding the base, so we won't call it
my ( $self, $c ) = @_;
my $req = $c->http_request;
if ( $c->get_option('add_consumer_auth_header') ) {
$self->$add_consumer_auth_header($req);
}
else {
my $token = $c->get_option('token') // $self->access_token // return;
$req->header(authorization => join ' ', Bearer => url_encode($token));
}
};
1;
__END__
=pod
=encoding UTF-8
=head1 NAME
Twitter::API::Trait::AppAuth - App-only (OAuth2) Authentication
=head1 VERSION
version 1.0006
=head1 SYNOPSIS
use Twitter::API;
my $client = Twitter::API->new_with_traits(
traits => [ qw/ApiMethods AppAuth/ ]);
my $r = $client->oauth2_token;
# return value is hash ref:
# { token_type => 'bearer', access_token => 'AA...' }
my $token = $r->{access_token};
# you can use the token explicitly with the -token argument:
my $user = $client->show_user('twitter_api', { -token => $token });
# or you can set the access_token attribute to use it implicitly
$client->access_token($token);
my $user = $client->show_user('twitterapi');
# to revoke a token
$client->invalidate_token($token);
# if you revoke the token stored in the access_token attribute, clear it:
$client->clear_access_token;
=head1 METHODS
=head2 oauth2_token
Call the C<oauth2/token> endpoint to get a bearer token. The token is not
stored in Twitter::API's state. If you want that, set the C<access_token>
attribute with the returned token.
See L<https://developer.twitter.com/en/docs/basics/authentication/api-reference/token> for details.
=head2 invalidate_token($token)
Calls the C<oauth2/invalidate_token> endpoint to revoke a token. See
L<https://developer.twitter.com/en/docs/basics/authentication/api-reference/invalidate_token> for
details.
=head1 AUTHOR
Marc Mims <[email protected]>
=head1 COPYRIGHT AND LICENSE
This software is copyright (c) 2015-2021 by Marc Mims.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
=cut