#perl #oauth-2.0 #google-api #google-calendar-api #google-oauth
#perl #oauth-2.0 #google-api #google-calendar-api #google-oauth
Вопрос:
Получены учетные данные для учетной записи службы из консоли разработчика
Сначала я преобразовал закрытый ключ p12 в PEM:
openssl pkcs12 -in <private key for Service Account>.p12 -out calendar.key -nocerts -nodes
Затем я запускаю:
use MIME::Base64;
use Crypt::OpenSSL::RSA;
use File::Slurp;
my $header = encode_base64('{"alg":"RS256","typ":"JWT"}','');
my $claim = encode_base64('{
"iss":"<mail for the Service Account>",
"scope":"https://www.googleapis.com/auth/calendar",
"aud":"https://accounts.google.com/o/oauth2/token",
"exp":'.(time() 3600).',
"iat":'.time().'
}','');
my $key = read_file('calendar.key');
my $rsa = Crypt::OpenSSL::RSA->new_private_key($key);
$rsa->use_sha256_hash;
$rsa->use_pkcs1_padding;
my $signature = encode_base64($rsa->sign($header . '.' . $claim), '');
my $token_request = $header . '.' . $claim . '.' . $signature;
print `curl -d 'grant_type=urn:ietf:params:oauth:grant-type:jwt-beareramp;assertion=$token_request' https://accounts.google.com/o/oauth2/token`;
Я получаю
{
"error" : "invalid_grant"
}
Я синхронизировал системное время с NTP, не помогло.
Ответ №1:
Я не знаю почему, но проблема была с curl
.
Я заменил его на WWW::Mechanize
:
my $mech = WWW::Mechanize->new( autocheck => 1 );
$mech->post('https://accounts.google.com/o/oauth2/token',
'Content-Type' => 'application/x-www-form-urlencoded',
'Content' => [
'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer',
'assertion' => $token_request,
],
);
и это работает.
Ответ №2:
На всякий случай, если кто-нибудь придет сюда в поисках способа получения токена на предъявителя из учетных данных учетной записи службы Google в текущем предоставленном файле JSON; вот фрагмент, который сработал у меня после того, как я не смог использовать Crypt :: JWT или Mojo :: JWT :: Google.
use LWP::UserAgent;
use JSON;
use Mojo::JWT;
use Mojo::File;
my $jwt = create_jwt_from_path_and_scopes( 'path/to/credentials.json', 'email https://www.googleapis.com/auth/compute' );
my $ua = LWP::UserAgent->new();
my $response = $ua->post('https://www.googleapis.com/oauth2/v4/token',
{ 'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer',
'assertion' => $jwt
}
);
#######################################################################
sub create_jwt_from_path_and_scopes
{
my ( $path, $scope ) = @_;
croak("No path provided") if not defined $path;
croak("$path no available") if not -f $path;
my $json = decode_json( Mojo::File->new($path)->slurp );
croak("No Private key in $path") if not defined $json->{private_key};
croak("Not a service account") if $json->{type} ne 'service_account';
my $jwt = Mojo::JWT->new();
$jwt->algorithm('RS256');
$jwt->secret($json->{private_key});
$jwt->claims( {
iss => $json->{client_email},
scope => $scope,
aud => 'https://www.googleapis.com/oauth2/v4/token',
iat => time(),
exp => time() 3600
} );
$jwt->set_iat( 1 );
return $jwt->encode;
}
#######################################################################
Комментарии:
1. Я столкнулся с аналогичной проблемой. Какова была точная причина, по которой вы не смогли использовать Crypt ::JWT? Я продолжаю получать странную ошибку зависимости, в которой говорится, что не удалось найти загружаемый CryptX.
2. Я мог бы поставить вам 100 баллов… даже я не искал тот же ответ… В любом случае, просто примечание — можно сгенерировать ключи в bash следующим образом:
jwt_private_key_file=~/.ssh/jwtRS256.key; jwt_public_key_file=~/.ssh/jwtRS256.key.pub; ssh-keygen -t rsa -b 4096 -m PEM -f $jwt_private_key_file ; openssl rsa -in $jwt_private_key_file -pubout -outform PEM -out $jwt_public_key_file
Ответ №3:
Измените свою команду curl на:
curl -H "Content-Type: application/x-www-form-urlencoded"
-d grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer
-d assertion=$token_request
https://accounts.google.com/oauth2/token
Ответ №4:
Попробуйте использовать BASE64URL вместо BASE64. В спецификациях JWT / JWS / JWE используется BASE64URL.
MIME::Base64 ---> MIME::Base64::URLSafe
encode_base64 ---> urlsafe_b64encode