Авторизация с помощью сервисного аккаунта


Рекомендуется для связи Сервер → Сервер

Пройдите первоначальную настройку проекта

Убедитесь, что выполнили все инструкции из раздела по добавлению проекта и приложения

Добавьте сервисный аккаунт

В проекте на вкладке "API и сервисы / Сервисные аккаунты" создайте новый аккаунт. По сути это отдельный пользователь Garpun, который имеет доступ к аккаунту вашей организации с максимальными правами, его действия будут логироваться как действия обычного пользователя.

Добавьте ключ доступа к сервисному аккаунту

После создания сервисного аккаунта вы попадаете на его карточку, там вы должны выпустить api-ключ.

Сохраните его в защищенном месте, так как если вы его потеряете — то с его помощью злоумышленники смогу получить доступ к вашему приложению.

Если это произошло — удалите ключ и доступ будет отозван в течение некоторго непродолжительного времени.

Вы можете добавить несколько ключей для вашего приложения, если это необходимо например для разных подсистем.

Получение токена

Чтобы работать с API нужно сгенерировать jwt токен с помощью сервисного аккаунта и обменять его на access_token для доступа в апи.

В этом случае у вас не будет refresh_token. Работает так (RFC5723):

  • вы генеририруете jwt_assertion токен у себя
  • отправляете его на сервер account.garpun.com
  • сервер проверяет jwt подпись и выдает вам access_token

Вы можете реализовать это вручную или с использованием Google Auth Lib. На текущий момент проверна работосполобность следующих способ для Java и Python

Генерация с помошью Google Auth Lib Java

google-auth-library-java

import com.google.auth.oauth2.AccessToken;
import com.google.auth.oauth2.GoogleCredentials;

import java.io.FileInputStream;
import java.util.Collections;

public class Main {

    public static void main(String[] args) throws Exception {
        String credFilename = "../creds.json";
        GoogleCredentials credentials = GoogleCredentials.fromStream(
                new FileInputStream(credFilename)
        );
        if (credentials.createScopedRequired()) {
            credentials = credentials.createScoped(Collections.singletonList("account-management"));
        }
        credentials.refreshIfExpired();
        AccessToken token = credentials.getAccessToken();
        System.out.println("token = " + token);
    }
}

Генерация с помошью Google Auth Lib Python

google-auth-library-python

from google.auth.transport.requests import Request
from google.oauth2 import service_account
from google.oauth2.service_account import Credentials

credFileName = "../creds.json"

credentials: Credentials = service_account.Credentials.from_service_account_file(
    credFileName,
    scopes=['account-management'],
)

credentials.refresh(Request())

print("credentials.token = %s" % str(credentials.token))

Генерация вручную на Python

import json
import time
import jwt
import requests

# Считываем доступы к dict
with open('creds.json', 'r') as f:
    sa = json.loads(f.read())

# Готовим данные для JWT
issuer_ = sa['client_email']
key_id = sa['private_key_id']
private_key = sa['private_key']

now = int(time.time())
payload = {
    'aud': sa['token_uri'],
    'iss': issuer_,
    'iat': now,
    'exp': now + 360
}

# Формирование JWT
encoded_token = jwt.encode(
    payload,
    private_key,
    algorithm='RS256',

    # передача kid ОБЯЗАТЕЛЬНА!
    headers={'kid': key_id})
jwt_assertion = str(encoded_token.decode('utf-8'))

# Получаем access token по подписанному вам jwt
token_url_ = payload['aud']
resp = requests.post(token_url_, data={
    "assertion": jwt_assertion,
    "grant_type": "urn:ietf:params:oauth:grant-type:jwt-bearer"
})
print("resp.status_code = %s" % str(resp.status_code))

if resp.ok:
    token_info = resp.json()
    print("access_token = %s" % str(token_info['access_token']))
    print("token_info = %s" % str(token_info))
else:
    print("resp.text = %s" % str(resp.text))

Локальное использование

Если возникла необходимость протестировать работу ключа сервисного аккаунта налокально запущеной Мете, необходимо учесть, что локальная Мета ожидает в качестве параметра aud ссылку на локальную же Мету (http://localhost:8080/oauth2/token), поэтому работать будет только ручной способ генерации JWT токена, который позволяет подставить нужный aud.