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

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

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

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

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

Обзор

Для поддержки межсерверных взаимодействий сначала создайте учетную запись службы для своего проекта в файле API Console. Если вы хотите получить доступ к пользовательским данным для пользователей в вашей учетной записи 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 Console. Чтобы сгенерировать учетные данные служебной учетной записи или просмотреть общедоступные учетные данные, которые вы уже создали, выполните следующие действия.

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

  1. Откройте Service accounts page.
  2. If prompted, select a project, or create a new one.
  3. Нажмите Создать сервисный аккаунт .
  4. В разделе « Сведения об учетной записи службы » введите имя, идентификатор и описание учетной записи службы, затем нажмите « Создать и продолжить ».
  5. Необязательно: в разделе « Предоставить этой учетной записи службы доступ к проекту » выберите роли IAM, которые необходимо предоставить учетной записи службы.
  6. Нажмите Продолжить .
  7. Необязательно: в разделе « Предоставить пользователям доступ к этой учетной записи службы » добавьте пользователей или группы, которым разрешено использовать учетную запись службы и управлять ею.
  8. Щелкните Готово .

Затем создайте ключ сервисной учетной записи:

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

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

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

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

Делегирование полномочий на уровне домена сервисному аккаунту

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

Чтобы делегировать сервисному аккаунту полномочия на уровне домена, суперадминистратор домена Google Workspace должен выполнить следующие действия:

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

Теперь ваше приложение имеет право совершать вызовы API от имени пользователя в вашем домене (чтобы «выдавать себя за» пользователя). Когда вы готовитесь к авторизованным вызовам API, вы указываете пользователя, который будет олицетворяться.

Подготовка к авторизованному вызову API

Джава

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

import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.services.sqladmin.SQLAdminScopes;

// ...

GoogleCredential credential = GoogleCredential.fromStream(new FileInputStream("MyProject-1234.json"))
    .createScoped(Collections.singleton(SQLAdminScopes.SQLSERVICE_ADMIN));

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

Делегирование полномочий на уровне домена

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

GoogleCredential credential = GoogleCredential.fromStream(new FileInputStream("MyProject-1234.json"))
    .createScoped(Collections.singleton(SQLAdminScopes.SQLSERVICE_ADMIN))
    .createDelegated("user@example.com");

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

питон

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

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

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

  2. Делегирование полномочий на уровне домена

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

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

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

HTTP/ОТДЫХ

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

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

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

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

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

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

В оставшейся части этого раздела описываются особенности создания 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

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

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

{"alg":"RS256","typ":"JWT"}

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

eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9
Формирование набора требований 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 и Base64url-safe. Ниже приведен пример 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 (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 Console. На выходе будет массив байтов.

Затем подпись должна быть закодирована в 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-адресе. 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 Google

Джава

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

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

питон

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

  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/ОТДЫХ

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

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

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

Вызов конечной точки drive.files (API Drive Files) с использованием 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. Сервисный аккаунт был авторизован с использованием адреса электронной почты клиента, а не идентификатора клиента (числового) в консоли администратора. На странице делегирования домена в консоли администратора удалите клиент и повторно добавьте его с числовым идентификатором.
access_denied (любое значение) Если вы используете делегирование на уровне домена, одна или несколько запрошенных областей не авторизованы в консоли администратора.

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

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

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

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

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

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

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

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

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

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

invalid_grant Not a valid email. Пользователь не существует. Убедитесь, что адрес электронной почты в 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 и убедитесь, что ключ, которым подписано утверждение, связан с учетной записью службы.

Попробуйте использовать предоставленную Google библиотеку OAuth, чтобы убедиться, что 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 Consoleи в разделе IAM & Admin > Service Accounts включите учетную запись службы, которая содержит «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, который вы хотите вызвать, имеет определение службы, опубликованное в репозитории GitHub API Google , вы можете выполнять авторизованные вызовы 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, а для поля exp укажите время ровно через 3600 секунд, когда истечет срок действия JWT.

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

Например:

Джава

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

GoogleCredential credential =
        GoogleCredential.fromStream(new FileInputStream("MyProject-1234.json"));
PrivateKey privateKey = credential.getServiceAccountPrivateKey();
String privateKeyId = credential.getServiceAccountPrivateKeyId();

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 ...

питон

Использование 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