Использование OAuth 2.0 для серверных приложений

Система Google OAuth 2.0 поддерживает взаимодействие между серверами, например, между веб-приложением и сервисом Google. Для этого сценария вам потребуется сервисный аккаунт , который принадлежит вашему приложению, а не отдельному конечному пользователю. Ваше приложение вызывает API Google от имени сервисного аккаунта, поэтому пользователи напрямую не участвуют в процессе. Этот сценарий иногда называют «двухэтапной авторизацией OAuth» или «2LO». (Соответствующий термин «трехэтапная авторизация OAuth» относится к сценариям, в которых ваше приложение вызывает API Google от имени конечных пользователей, и в которых иногда требуется согласие пользователя.)

Дополнительную информацию см. в разделе «Рекомендации по использованию служебных учетных записей» .

Как правило, приложение использует сервисный аккаунт, когда оно применяет API Google для работы со своими собственными данными, а не с данными пользователя. Например, приложение, использующее Google Cloud Datastore для хранения данных, будет использовать сервисный аккаунт для аутентификации своих вызовов к API Google Cloud Datastore.

Администраторы домена Google Workspace также могут предоставлять учетным записям служб права доступа к данным пользователей в масштабе всего домена от имени пользователей этого домена.

В этом документе описывается, как приложение может выполнить протокол OAuth 2.0 между серверами, используя либо клиентскую библиотеку Google API (рекомендуется), либо протокол HTTP.

Обзор

Для поддержки взаимодействия между серверами сначала создайте учетную запись службы для вашего проекта в консоли API. Если вы хотите получить доступ к данным пользователей в вашей учетной записи Google Workspace, предоставьте учетной записи службы доступ на уровне всего домена.

Затем ваше приложение подготавливается к выполнению авторизованных вызовов API, используя учетные данные сервисной учетной записи для запроса токена доступа у сервера аутентификации OAuth 2.0.

Наконец, ваше приложение сможет использовать токен доступа для вызова API Google.

Создайте учетную запись службы

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

Если ваше приложение работает на Google App Engine, учетная запись службы создается автоматически при создании проекта.

Если ваше приложение работает на Google Compute Engine, учетная запись службы также автоматически настраивается при создании проекта, но вам необходимо указать области доступа, к которым должно иметь доступ ваше приложение, при создании экземпляра Google Compute Engine. Для получения дополнительной информации см. раздел «Подготовка экземпляра для использования учетных записей служб» .

Если ваше приложение не работает на Google App Engine или Google Compute Engine, вам необходимо получить эти учетные данные в консоли Google API. Чтобы сгенерировать учетные данные сервисной учетной записи или просмотреть уже сгенерированные общедоступные учетные данные, выполните следующие действия:

Сначала создайте учетную запись службы:

  1. Откройте страницу « Учетные записи служб» .
  2. При появлении запроса выберите проект или создайте новый.
  3. Нажмите . Создайте учетную запись службы .
  4. В разделе «Сведения об учетной записи службы» введите имя, идентификатор и описание для учетной записи службы, затем нажмите «Создать и продолжить» .
  5. Необязательно: в разделе «Предоставить этой учетной записи службы доступ к проекту» выберите роли IAM, которые необходимо предоставить учетной записи службы.
  6. Нажмите «Продолжить» .
  7. Необязательно: в разделе «Предоставить пользователям доступ к этой учетной записи службы» добавьте пользователей или группы, которым разрешено использовать и управлять этой учетной записью службы.
  8. Нажмите «Готово» .

Далее создайте ключ учетной записи службы:

  1. Щелкните по адресу электронной почты созданной вами учетной записи службы.
  2. Нажмите вкладку « Клавиши» .
  3. В раскрывающемся списке «Добавить ключ» выберите «Создать новый ключ» .
  4. Нажмите «Создать» .

Для получения более подробной информации см. раздел «Рекомендации по управлению ключами учетных записей служб» .

Вы можете в любое время вернуться в консоль API , чтобы просмотреть адрес электронной почты, отпечатки открытого ключа и другую информацию, а также сгенерировать дополнительные пары открытого/закрытого ключа. Более подробную информацию об учетных данных сервисных учетных записей в консоли API см. в разделе «Сервисные учетные записи» в справочном файле консоли API.

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

Передайте служебной учетной записи полномочия, действующие в масштабе всего домена.

Используя учетную запись Google Workspace, администратор Workspace в организации может разрешить приложению доступ к данным пользователей Workspace от имени пользователей в домене Google Workspace. Например, приложение, использующее API Google Calendar для добавления событий в календари всех пользователей в домене Google Workspace, будет использовать служебную учетную запись для доступа к API Google Calendar от имени пользователей. Разрешение служебной учетной записи на доступ к данным от имени пользователей в домене иногда называют «делегированием полномочий в масштабах всего домена» служебной учетной записи.

Для делегирования полномочий в масштабах всего домена учетной записи службы суперадминистратор домена Google Workspace должен выполнить следующие действия:

  1. В консоли администратора вашего домена Google Workspace перейдите в главное > Безопасность > Доступ и контроль данных > Управление API .
  2. В панели «Делегирование на уровне домена» выберите «Управление делегированием на уровне домена» .
  3. Нажмите «Добавить новый» .
  4. В поле «Идентификатор клиента» введите идентификатор клиента учетной записи службы. Идентификатор клиента вашей учетной записи службы можно найти на странице «Учетные записи служб» .
  5. В поле «Области действия OAuth (разделенные запятыми)» введите список областей действия, к которым вашему приложению должен быть предоставлен доступ. Например, если вашему приложению необходим полный доступ к API Google Drive и API Google Calendar в масштабе всего домена, введите: https://www.googleapis.com/auth/drive, https://www.googleapis.com/auth/calendar .
  6. Нажмите «Авторизовать» .

Теперь ваше приложение имеет право выполнять вызовы API от имени пользователей вашего домена Workspace (для "выдачи себя за" пользователей). При подготовке к выполнению этих делегированных вызовов API вам необходимо явно указать пользователя, за которого нужно выдавать себя.

Выполните делегированный вызов API.

В следующих разделах показано, как выполнить авторизованный вызов API с помощью клиентской библиотеки Google API или путем прямого взаимодействия с системой OAuth 2.0 по протоколу HTTP.

Java

После получения адреса электронной почты клиента и закрытого ключа из консоли API используйте библиотеку Google Auth Library for Java для создания объекта GoogleCredentials на основе учетных данных сервисной учетной записи и областей доступа, необходимых вашему приложению. Например:

import com.google.auth.oauth2.GoogleCredentials;
import com.google.api.services.sqladmin.SQLAdminScopes;

// ...

GoogleCredentials credentials = GoogleCredentials.fromStream(new FileInputStream("ServiceAccountKey.json"))
    .createScoped(Collections.singleton(SQLAdminScopes.SQLSERVICE_ADMIN));

Если вы разрабатываете приложение в Google Cloud, вы можете использовать учетные данные приложения по умолчанию , что упростит процесс.

Делегировать полномочия в масштабах всего домена

Если у вас есть делегированный доступ к учетной записи службы на уровне домена и вы хотите выдать себя за учетную запись пользователя, укажите адрес электронной почты этой учетной записи пользователя в методе createDelegated объекта GoogleCredentials . Например:

GoogleCredentials credentials = GoogleCredentials.fromStream(new FileInputStream("ServiceAccountKey.json"))
    .createScoped(Collections.singleton(SQLAdminScopes.SQLSERVICE_ADMIN))
    .createDelegated("workspace-user@example.com");

Объект GoogleCredentials используется для вызова метода createDelegated() . Аргументом метода createDelegated() должен быть пользователь, принадлежащий к вашей учетной записи Workspace. Ваш код, выполняющий запрос, будет использовать эти учетные данные для вызова API Google, используя вашу учетную запись службы.

Python

После получения адреса электронной почты клиента и закрытого ключа из консоли API, используйте клиентскую библиотеку Google API для Python , чтобы выполнить следующие шаги:

  1. Создайте объект Credentials используя учетные данные сервисной учетной записи и области доступа, необходимые вашему приложению. Например:
    from google.oauth2 import service_account
    
    SCOPES = ['https://www.googleapis.com/auth/sqlservice.admin']
    SERVICE_ACCOUNT_FILE = '/path/to/ServiceAccountKey.json'
    
    credentials = service_account.Credentials.from_service_account_file(
            SERVICE_ACCOUNT_FILE, scopes=SCOPES)

    Если вы разрабатываете приложение в Google Cloud, вы можете использовать учетные данные приложения по умолчанию , что упростит процесс.

  2. Делегировать полномочия в масштабах всего домена

    Если вы делегировали учетную запись службы доступ на уровне домена и хотите выдать себя за учетную запись пользователя, используйте метод with_subject существующего объекта ServiceAccountCredentials . Например:

    delegated_credentials = credentials.with_subject('user@example.org')

Используйте объект Credentials для вызова API Google в вашем приложении.

HTTP/REST

После получения идентификатора клиента и закрытого ключа из консоли API вашему приложению необходимо выполнить следующие шаги:

  1. Создайте JSON Web Token (JWT, произносится как «джот»), который включает заголовок, набор утверждений и подпись.
  2. Запросите токен доступа у сервера авторизации Google OAuth 2.0.
  3. Обработайте JSON-ответ, который возвращает сервер авторизации.

В следующих разделах описано, как выполнить эти шаги.

Если ответ содержит токен доступа, вы можете использовать его для вызова API Google . (Если ответ не содержит токен доступа, ваш запрос JWT и токена может быть сформирован неправильно, или у учетной записи службы может отсутствовать разрешение на доступ к запрошенным областям действия.)

Когда срок действия токена доступа истекает , ваше приложение генерирует новый JWT, подписывает его и запрашивает еще один токен доступа.

Ваше серверное приложение использует JWT для запроса токена у сервера авторизации Google,  а затем использует этот токен для вызова конечной точки API Google. Конечный пользователь не участвует.
Рисунок 1. Ваше серверное приложение использует JWT для запроса токена у сервера авторизации Google, а затем использует этот токен для вызова конечной точки API Google. Конечный пользователь не участвует в процессе.

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

Создать JWT

JWT состоит из трех частей: заголовка, набора утверждений и подписи. Заголовок и набор утверждений представляют собой объекты JSON. Эти объекты JSON сериализуются в байты UTF-8, а затем кодируются с использованием кодировки Base64url. Эта кодировка обеспечивает устойчивость к изменениям кодировки из-за повторных операций кодирования. Заголовок, набор утверждений и подпись объединяются вместе с помощью символа точки ( . ).

JWT-вектор формируется следующим образом:

{Base64url encoded header}.{Base64url encoded claim set}.{Base64url encoded signature}

Базовая строка для подписи выглядит следующим образом:

{Base64url encoded header}.{Base64url encoded claim set}
Сформируйте заголовок JWT.

Заголовок состоит из двух обязательных полей: алгоритма подписи и формата утверждения, а также необязательного идентификатора ключа:

  • Алгоритм является обязательным и имеет только одно значение: "alg": "RS256" .
  • Формат является обязательным и имеет только одно значение: "typ": "JWT" .
  • Идентификатор ключа (Key ID) является необязательным и представляет собой идентификатор ключа учетной записи службы, используемой для подписи JWT. Если указан неверный идентификатор ключа, будут предприняты попытки использовать все ключи, связанные с учетной записью службы. Если действительный ключ не найден, токен отклоняется. Google оставляет за собой право отклонять токены с неверными идентификаторами ключей.

Сервисные учетные записи используют алгоритм RSA SHA-256 и формат токенов JWT. В результате, JSON-представление заголовка выглядит следующим образом:

{"alg":"RS256","typ":"JWT", "kid":"370ab79b4513eb9bad7c9bd16a95cb76b5b2a56a"}

В формате Base64url это выглядит следующим образом:

eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsICJraWQiOiIzNzBhYjc5YjQ1MTNlYjliYWQ3YzliZDE2YTk1Y2I3NmI1YjJhNTZhIn0=
Сформируйте набор претензий JWT.

Набор утверждений JWT содержит информацию о JWT, включая запрашиваемые разрешения (области действия), цель токена, эмитента, время выпуска токена и срок его действия. Большинство полей являются обязательными. Как и заголовок JWT, набор утверждений JWT представляет собой объект JSON и используется при вычислении подписи.

Обязательные заявления

Обязательные пункты формулы изобретения в наборе пунктов формулы изобретения JWT могут располагаться в любом порядке.

Имя Описание
iss Адрес электронной почты учетной записи службы поддержки.
scope Список разрешений, разделенных пробелами, которые запрашивает приложение.
aud Описание предполагаемого объекта утверждения. При запросе токена доступа это значение всегда равно https://oauth2.googleapis.com/token .
exp Время истечения срока действия утверждения, указанное в секундах с 00:00:00 UTC 1 января 1970 года. Это значение может превышать 1 час после времени выдачи.
iat Время, указанное в секундах с 00:00:00 UTC 1 января 1970 года.

Это пример JSON-представления обязательных полей в наборе утверждений JWT:

{
  "iss": "761326798069-r5mljlln1rd4lrbhg75efgigp36m78j5@developer.gserviceaccount.com",
  "scope": "https://www.googleapis.com/auth/devstorage.read_only",
  "aud": "https://oauth2.googleapis.com/token",
  "exp": 1328554385,
  "iat": 1328550785
}
Дополнительные претензии

В некоторых корпоративных сценариях приложение может использовать делегирование на уровне домена для действий от имени конкретного пользователя в организации. Разрешение на выполнение такого типа имитации пользователя должно быть предоставлено до того, как приложение сможет имитировать действия пользователя, и обычно это обрабатывается суперадминистратором. Для получения дополнительной информации см. раздел «Управление доступом к API с помощью делегирования на уровне домена» .

Для получения токена доступа, предоставляющего приложению делегированный доступ к ресурсу, укажите адрес электронной почты пользователя в наборе утверждений JWT в качестве значения sub .

Имя Описание
sub Адрес электронной почты пользователя, для которого приложение запрашивает делегированный доступ.

Если у приложения нет разрешения на имитацию пользователя, ответ на запрос токена доступа, содержащий sub , будет содержать ошибку .

Это пример набора утверждений JWT, включающего в себя sub :

{
  "iss": "761326798069-r5mljlln1rd4lrbhg75efgigp36m78j5@developer.gserviceaccount.com",
  "sub": "some.user@example.com",
  "scope": "https://www.googleapis.com/auth/prediction",
  "aud": "https://oauth2.googleapis.com/token",
  "exp": 1328554385,
  "iat": 1328550785
}
Кодирование набора утверждений JWT

Подобно заголовку JWT, набор утверждений JWT должен быть сериализован в UTF-8 и закодирован в формате Base64, безопасном для URL-адресов. Вот пример JSON-представления набора утверждений JWT:

{
  "iss": "761326798069-r5mljlln1rd4lrbhg75efgigp36m78j5@developer.gserviceaccount.com",
  "scope": "https://www.googleapis.com/auth/prediction",
  "aud": "https://oauth2.googleapis.com/token",
  "exp": 1328554385,
  "iat": 1328550785
}
Вычислите подпись

JSON Web Signature (JWS) — это спецификация, определяющая механику генерации подписи для JWT. Входными данными для подписи является массив байтов следующего содержимого:

{Base64url encoded header}.{Base64url encoded claim set}

Алгоритм подписи, указанный в заголовке JWT, должен использоваться при вычислении подписи. Единственный алгоритм подписи, поддерживаемый сервером авторизации Google OAuth 2.0, — это RSA с использованием алгоритма хеширования SHA-256. Он обозначается как RS256 в поле alg заголовка JWT.

Подпишите представление входных данных в кодировке UTF-8 с помощью алгоритма SHA256withRSA (также известного как RSASSA-PKCS1-V1_5-SIGN с хеш-функцией SHA-256) закрытым ключом, полученным из консоли Google API . Результатом будет массив байтов.

Затем подпись необходимо закодировать в Base64url. Заголовок, набор утверждений и подпись объединяются вместе с помощью символа точки ( . ). В результате получается JWT. Он должен выглядеть следующим образом (для ясности добавлены переносы строк):

{Base64url encoded header}.
{Base64url encoded claim set}.
{Base64url encoded signature}

Это пример JWT до кодирования Base64url:

{"alg":"RS256","typ":"JWT"}.
{
"iss":"761326798069-r5mljlln1rd4lrbhg75efgigp36m78j5@developer.gserviceaccount.com",
"scope":"https://www.googleapis.com/auth/prediction",
"aud":"https://oauth2.googleapis.com/token",
"exp":1328554385,
"iat":1328550785
}.
[signature bytes]

Это пример подписанного JWT-токена, готового к передаче:

eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiI3NjEzMjY3OTgwNjktcjVtbGpsbG4xcmQ0bHJiaGc3NWVmZ2lncDM2bTc4ajVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzY29wZSI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2F1dGgvcHJlZGljdGlvbiIsImF1ZCI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL29hdXRoMi92NC90b2tlbiIsImV4cCI6MTMyODU1NDM4NSwiaWF0IjoxMzI4NTUwNzg1fQ.UFUt59SUM2_AW4cRU8Y0BYVQsNTo4n7AFsNrqOpYiICDu37vVt-tw38UKzjmUKtcRsLLjrR3gFW3dNDMx_pL9DVjgVHDdYirtrCekUHOYoa1CMR66nxep5q5cBQ4y4u2kIgSvChCTc9pmLLNoIem-ruCecAJYgI9Ks7pTnW1gkOKs0x3YpiLpzplVHAkkHztaXiJdtpBcY1OXyo6jTQCa3Lk2Q3va1dPkh_d--GU2M5flgd8xNBPYw4vxyt0mP59XZlHMpztZt0soSgObf7G3GXArreF_6tpbFsS3z2t5zkEiHuWJXpzcYr5zWTRPDEHsejeBSG8EgpLDce2380ROQ

Запросить токен доступа

После генерации подписанного JWT приложение может использовать его для запроса токена доступа. Этот запрос токена доступа представляет собой HTTPS POST запрос, а тело запроса закодировано в формате URL. Например:

https://oauth2.googleapis.com/token

В HTTPS POST запросе требуются следующие параметры:

Имя Описание
grant_type Используйте следующую строку, закодированную в формате URL, если это необходимо: urn:ietf:params:oauth:grant-type:jwt-bearer
assertion JWT, включая подпись.

Это необработанный дамп HTTPS POST запроса, использованного при запросе токена доступа:

POST /token HTTP/1.1
Host: oauth2.googleapis.com
Content-Type: application/x-www-form-urlencoded

grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiI3NjEzMjY3OTgwNjktcjVtbGpsbG4xcmQ0bHJiaGc3NWVmZ2lncDM2bTc4ajVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzY29wZSI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2F1dGgvcHJlZGljdGlvbiIsImF1ZCI6Imh0dHBzOi8vYWNjb3VudHMuZ29vZ2xlLmNvbS9vL29hdXRoMi90b2tlbiIsImV4cCI6MTMyODU3MzM4MSwiaWF0IjoxMzI4NTY5NzgxfQ.ixOUGehweEVX_UKXv5BbbwVEdcz6AYS-6uQV6fGorGKrHf3LIJnyREw9evE-gs2bmMaQI5_UbabvI4k-mQE4kBqtmSpTzxYBL1TCd7Kv5nTZoUC1CmwmWCFqT9RE6D7XSgPUh_jF1qskLa2w0rxMSjwruNKbysgRNctZPln7cqQ

Это тот же самый запрос, выполненный с помощью curl :

curl -d 'grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiI3NjEzMjY3OTgwNjktcjVtbGpsbG4xcmQ0bHJiaGc3NWVmZ2lncDM2bTc4ajVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzY29wZSI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2F1dGgvcHJlZGljdGlvbiIsImF1ZCI6Imh0dHBzOi8vYWNjb3VudHMuZ29vZ2xlLmNvbS9vL29hdXRoMi90b2tlbiIsImV4cCI6MTMyODU3MzM4MSwiaWF0IjoxMzI4NTY5NzgxfQ.RZVpzWygMLuL-n3GwjW1_yhQhrqDacyvaXkuf8HcJl8EtXYjGjMaW5oiM5cgAaIorrqgYlp4DPF_GuncFqg9uDZrx7pMmCZ_yHfxhSCXru3gbXrZvAIicNQZMFxrEEn4REVuq7DjkTMyCMGCY1dpMa8aWfTQFt3Eh7smLchaZsU
' https://oauth2.googleapis.com/token

Обработка ответа

Если запрос JWT и токена доступа сформирован корректно, и у учетной записи службы есть разрешение на выполнение операции, то JSON-ответ от сервера авторизации будет включать токен доступа. Ниже приведен пример ответа:

{
  "access_token": "1/8xbJqaOZXSUZbHLl5EOtu1pxz3fmmetKx9W8CV4t79M",
  "scope": "https://www.googleapis.com/auth/prediction"
  "token_type": "Bearer",
  "expires_in": 3600
}

Токены доступа можно использовать повторно в течение периода времени, указанного значением expires_in .

Важный аспект безопасности: понимание процесса выдачи себя за другое лицо.

При делегировании полномочий в масштабах всего домена вы не предоставляете учетной записи службы прямой доступ ко всем данным пользователей. Вместо этого вы разрешаете ей выдавать себя за конкретных пользователей при выполнении вызовов API.
  • Доступ предоставляется от имени пользователя: ваше приложение должно указывать, от имени какого пользователя следует выполнять каждый API-запрос. Затем приложение действует с правами этого конкретного пользователя, а не с какими-либо повышенными или общедоменными привилегиями .
  • Ограниченные права доступа: доступ учетной записи службы ограничен двумя факторами: правами пользователя, от имени которого осуществляется авторизация, и областями действия OAuth, которые вы разрешаете в консоли администратора. Она не может получить доступ к данным, к которым сам пользователь, от имени которого осуществляется авторизация, не имеет доступа.
  • Принцип минимальных привилегий: поскольку эта функция позволяет получать доступ к данным пользователя без его прямого согласия, крайне важно следовать передовым методам обеспечения безопасности. Предоставляйте доступ только к необходимым областям OAuth и убедитесь, что вы понимаете последствия для безопасности.
Подробные рекомендации по обеспечению безопасности см. в разделе «Рекомендации по делегированию полномочий в масштабе домена».

Вызов API Google

Java

Для вызова API Google используйте объект GoogleCredentials , выполнив следующие шаги:

  1. Создайте объект сервиса для API, который вы хотите вызвать, используя объект GoogleCredentials . Например:
    SQLAdmin sqladmin =
        new SQLAdmin.Builder(httpTransport, JSON_FACTORY, credentials).build();
  2. Отправляйте запросы к API-сервису, используя интерфейс, предоставляемый объектом сервиса . Например, чтобы вывести список экземпляров баз данных Cloud SQL в проекте exciting-example-123:
    SQLAdmin.Instances.List instances =
        sqladmin.instances().list("exciting-example-123").execute();

Python

Для вызова API Google используйте объект Credentials , выполнив следующие шаги:

  1. Создайте объект сервиса для API, который вы хотите вызвать. Для этого вызовите функцию build , указав имя и версию API, а также объект авторизованных Credentials . Например, для вызова версии 1beta3 API администрирования Cloud SQL:
    import googleapiclient.discovery
    
    sqladmin = googleapiclient.discovery.build('sqladmin', 'v1beta3', credentials=credentials)
  2. Отправляйте запросы к API-сервису, используя интерфейс, предоставляемый объектом сервиса . Например, чтобы вывести список экземпляров баз данных Cloud SQL в проекте exciting-example-123:
    response = sqladmin.instances().list(project='exciting-example-123').execute()

HTTP/REST

После получения токена доступа ваше приложение может использовать его для вызова API Google от имени определенной учетной записи службы или учетной записи пользователя, если предоставлены необходимые для API права доступа. Для этого включите токен доступа в запрос к API, указав либо параметр запроса access_token , либо значение Bearer в заголовке HTTP Authorization . По возможности предпочтительнее использовать заголовок HTTP, поскольку строки запроса обычно видны в логах сервера. В большинстве случаев вы можете использовать клиентскую библиотеку для настройки вызовов к API Google (например, при вызове API файлов Google Drive ).

Вы можете протестировать все API Google и ознакомиться с их областями действия на платформе OAuth 2.0 Playground .

Примеры HTTP GET-запросов

Вызов конечной точки drive.files (API файлового сервиса Drive) с использованием HTTP-заголовка Authorization: Bearer может выглядеть следующим образом. Обратите внимание, что вам необходимо указать собственный токен доступа:

GET /drive/v2/files HTTP/1.1
Host: www.googleapis.com
Authorization: Bearer access_token

Вот вызов того же API для аутентифицированного пользователя с использованием параметра строки запроса access_token :

GET https://www.googleapis.com/drive/v2/files?access_token=access_token

примеры curl

Вы можете протестировать эти команды с помощью приложения командной строки curl . Вот пример, использующий опцию заголовка HTTP (предпочтительный вариант):

curl -H "Authorization: Bearer access_token" https://www.googleapis.com/drive/v2/files

Или, в качестве альтернативы, можно использовать параметр строки запроса:

curl https://www.googleapis.com/drive/v2/files?access_token=access_token

Когда истекает срок действия токенов доступа

Токены доступа, выданные сервером авторизации Google OAuth 2.0, истекают по истечении срока действия, указанного в значении expires_in . По истечении срока действия токена доступа приложение должно сгенерировать новый JWT, подписать его и запросить новый токен доступа.

коды ошибок JWT

поле error поле error_description Значение Как решить проблему?
unauthorized_client Unauthorized client or scope in request. Если вы пытаетесь использовать делегирование на уровне домена, значит, учетная запись службы не авторизована в консоли администратора домена пользователя.

Убедитесь, что учетная запись службы авторизована на странице «Делегирование в масштабе домена» в консоли администратора для пользователя в поле « sub ».

Обычно это занимает несколько минут, но для распространения авторизации на всех пользователей вашей учетной записи Google может потребоваться до 24 часов.

unauthorized_client Client is unauthorized to retrieve access tokens using this method, or client not authorized for any of the scopes requested. Авторизация учетной записи службы осуществлялась либо с использованием адреса электронной почты клиента, а не идентификатора клиента (числового значения) в консоли администратора, либо с использованием группы Google для авторизации. На странице «Делегирование на уровне домена» в консоли администратора удалите клиент и добавьте его заново, указав числовой идентификатор, или удалите группу Google и замените ее отдельной службой или учетной записью пользователя.
access_denied (любое значение) Если вы используете делегирование на уровне домена, одна или несколько запрошенных областей доступа не будут авторизованы в консоли администратора.

Убедитесь, что учетная запись службы авторизована на странице делегирования в масштабе домена в консоли администратора для пользователя, указанного в поле sub claim, и что она включает все области действия, которые вы запрашиваете в поле scope claim вашего JWT.

Убедитесь, что доступ к сервисам Google не ограничен, просмотрев раздел «Управление доступом к сервисам, которые не контролируются индивидуально» .

Обычно это занимает несколько минут, но для распространения авторизации на всех пользователей вашей учетной записи Google может потребоваться до 24 часов.

admin_policy_enforced (любое значение) Учетная запись Google не может авторизовать одну или несколько запрошенных областей действия из-за правил администратора Google Workspace.

Дополнительную информацию о том, как администратор может ограничить доступ ко всем областям действия или к конфиденциальным и ограниченным областям действия до тех пор, пока доступ не будет явно предоставлен вашему идентификатору клиента OAuth, см. в справочной статье Google Workspace Admin «Управление доступом сторонних и внутренних приложений к данным Google Workspace».

invalid_client (любое значение)

Клиент OAuth или токен JWT недействителен или неправильно настроен.

Подробности см. в описании ошибки.

Убедитесь, что JWT-токен действителен и содержит корректные утверждения.

Убедитесь, что клиент OAuth и учетная запись службы настроены правильно и что вы используете корректный адрес электронной почты.

Убедитесь, что JWT-токен корректен и был выдан для идентификатора клиента, указанного в запросе.

deleted_client (любое значение)

Клиент OAuth, использованный для отправки запроса, был удален. Удаление может произойти вручную или автоматически в случае неиспользуемых клиентов . Удаленные клиенты могут быть восстановлены в течение 30 дней с момента удаления. Подробнее .

Используйте идентификатор клиента, который все еще активен.

invalid_grant Not a valid email , Invalid email or User ID. Пользователя не существует. Убедитесь, что адрес электронной почты в поле ( sub ) указан правильно.
invalid_grant

Invalid JWT: Token must be a short-lived token (60 minutes) and in a reasonable timeframe. Check your 'iat' and 'exp' values and use a clock with skew to account for clock differences between systems.

Обычно это означает, что локальное системное время некорректно. Это также может произойти, если значение exp отстоит более чем на 65 минут от значения iat или если значение exp меньше значения iat .

Убедитесь, что часы в системе, где генерируется JWT, установлены правильно. При необходимости синхронизируйте время с Google NTP .

invalid_grant Invalid JWT Signature.

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

В качестве альтернативы, утверждение JWT может быть закодировано неправильно — оно должно быть закодировано в Base64, без символов новой строки и знаков равенства.

Расшифруйте набор утверждений JWT и убедитесь, что ключ, которым подписано утверждение, связан с учетной записью службы.

Попробуйте использовать библиотеку OAuth, предоставленную Google, чтобы убедиться в корректной генерации JWT.

invalid_scope Invalid OAuth scope or ID token audience provided. Запросы на добавление областей действия не поступали (пустой список областей действия), или одна из запрошенных областей действия не существует (т.е. является недействительной).

Убедитесь, что поле scope (утверждение области видимости) JWT заполнено, и сравните содержащиеся в нем области видимости с документированными областями видимости для используемых вами API, чтобы исключить ошибки и опечатки.

Обратите внимание, что список областей видимости в утверждении scope должен быть разделен пробелами, а не запятыми.

disabled_client The OAuth client was disabled. Ключ, используемый для подписи утверждения JWT, отключен.

Перейдите в консоль Google API и в разделе IAM & Admin > Service Accounts включите учетную запись службы, содержащую "Key ID", используемый для подписи утверждения.

org_internal This client is restricted to users within its organization. Идентификатор клиента OAuth в запросе является частью проекта, ограничивающего доступ к учетным записям Google в конкретной организации Google Cloud .

Для аутентификации используйте служебную учетную запись организации. Подтвердите конфигурацию типа пользователя для вашего приложения OAuth.

Дополнение: Авторизация служебной учетной записи без OAuth.

В некоторых API Google можно выполнять авторизованные вызовы API, используя подписанный JWT непосредственно в качестве токена доступа, а не токен доступа OAuth 2.0. В таких случаях можно избежать необходимости отправлять сетевой запрос на сервер авторизации Google перед выполнением вызова API.

Если для API, к которому вы хотите обратиться, опубликовано определение сервиса в репозитории Google API на GitHub , вы можете выполнять авторизованные вызовы API, используя JWT вместо токена доступа. Для этого:

  1. Создайте учетную запись службы . Обязательно сохраните JSON-файл, полученный при создании учетной записи.
  2. Используя любую стандартную библиотеку для создания JWT, например, ту, что находится на jwt.io , создайте JWT с заголовком и полезной нагрузкой, как в следующем примере:
    {
      "alg": "RS256",
      "typ": "JWT",
      "kid": "abcdef1234567890"
    }
    .
    {
      "iss": "123456-compute@developer.gserviceaccount.com",
      "sub": "123456-compute@developer.gserviceaccount.com",
      "aud": "https://firestore.googleapis.com/",
      "iat": 1511900000,
      "exp": 1511903600
    }
    • В поле kid в заголовке укажите идентификатор закрытого ключа вашей учетной записи службы. Это значение можно найти в поле private_key_id файла JSON вашей учетной записи службы.
    • В полях iss и sub укажите адрес электронной почты вашей учетной записи службы. Это значение можно найти в поле client_email вашего JSON-файла учетной записи службы. Это значение однозначно идентифицирует клиента и, по сути, является идентификатором клиента.
    • В поле aud укажите конечную точку API. Например: https:// SERVICE .googleapis.com/ .
    • В поле iat укажите текущее время Unix epoch, а в поле exp время ровно через 3600 секунд, когда истечет срок действия JWT.

Подпишите JWT с помощью RSA-256, используя закрытый ключ, найденный в JSON-файле вашей учетной записи службы.

Например:

Java

Использование google-auth-library-java и java-jwt :

import com.google.auth.oauth2.ServiceAccountCredentials;
...
GoogleCredentials credentials =
        GoogleCredentials.fromStream(new FileInputStream("MyProject-1234.json"));
PrivateKey privateKey = ((ServiceAccountCredentials) credentials).getPrivateKey();
String privateKeyId = ((ServiceAccountCredentials) credentials).getPrivateKeyId();

long now = System.currentTimeMillis();

try {
    Algorithm algorithm = Algorithm.RSA256(null, privateKey);
    String signedJwt = JWT.create()
        .withKeyId(privateKeyId)
        .withIssuer("123456-compute@developer.gserviceaccount.com")
        .withSubject("123456-compute@developer.gserviceaccount.com")
        .withAudience("https://firestore.googleapis.com/")
        .withIssuedAt(new Date(now))
        .withExpiresAt(new Date(now + 3600 * 1000L))
        .sign(algorithm);
} catch ...

Python

Использование PyJWT :

iat = time.time()
exp = iat + 3600
payload = {'iss': '123456-compute@developer.gserviceaccount.com',
           'sub': '123456-compute@developer.gserviceaccount.com',
           'aud': 'https://firestore.googleapis.com/',
           'iat': iat,
           'exp': exp}
additional_headers = {'kid': PRIVATE_KEY_ID_FROM_JSON}
signed_jwt = jwt.encode(payload, PRIVATE_KEY_FROM_JSON, headers=additional_headers,
                       algorithm='RS256')
  1. Вызовите API, используя подписанный JWT в качестве токена носителя:
    GET /v1/projects/abc/databases/123/indexes HTTP/1.1
    Authorization: Bearer SIGNED_JWT
    Host: firestore.googleapis.com

Внедрить защиту от межсетевых атак

Дополнительным шагом для защиты учетных записей пользователей является внедрение защиты от изменений в учетных записях с помощью сервиса Google Cross-Account Protection. Этот сервис позволяет подписаться на уведомления о событиях безопасности, которые предоставляют вашему приложению информацию о важных изменениях в учетной записи пользователя. Затем вы можете использовать эту информацию для принятия мер в зависимости от того, как вы решите реагировать на события.

Вот несколько примеров типов событий, отправляемых вашему приложению службой защиты от межсетевых атак Google:

  • https://schemas.openid.net/secevent/risc/event-type/sessions-revoked
  • https://schemas.openid.net/secevent/oauth/event-type/token-revoked
  • https://schemas.openid.net/secevent/risc/event-type/account-disabled

Дополнительную информацию о том, как реализовать защиту от межсетевых атак, а также полный список доступных событий см. на странице «Защита учетных записей пользователей с помощью межсетевой защиты».