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

В этом документе объясняется, как веб-серверные приложения используют клиентские библиотеки Google API или конечные точки Google OAuth 2.0 для реализации авторизации OAuth 2.0 для доступа к YouTube Data API.

OAuth 2.0 позволяет пользователям обмениваться определенными данными с приложением, сохраняя при этом конфиденциальность своих имен пользователей, паролей и другой информации. Например, приложение может использовать OAuth 2.0 для получения разрешения на загрузку видео на YouTube-канал пользователя.

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

Приложения веб-серверов часто также используют сервисные учетные записи для авторизации запросов API, особенно при вызове облачных API для доступа к данным проекта, а не к данным конкретного пользователя. Приложения веб-серверов могут использовать сервисные учетные записи в сочетании с авторизацией пользователей. Обратите внимание, что API данных YouTube поддерживает поток сервисных учетных записей только для владельцев контента YouTube, которые владеют и управляют несколькими каналами YouTube. В частности, владельцы контента могут использовать сервисные учетные записи для вызова методов API, поддерживающих параметр запроса onBehalfOfContentOwner .

Клиентские библиотеки

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

При использовании клиентской библиотеки Google API для обработки потока OAuth 2.0 в вашем приложении, библиотека выполняет множество действий, которые в противном случае приложению пришлось бы обрабатывать самостоятельно. Например, она определяет, когда приложение может использовать или обновлять сохраненные токены доступа, а также когда приложению необходимо повторно получить согласие. Клиентская библиотека также генерирует корректные URL-адреса перенаправления и помогает реализовать обработчики перенаправлений, которые обменивают коды авторизации на токены доступа.

Клиентские библиотеки Google API для серверных приложений доступны для следующих языков:

Предварительные требования

Включите API для вашего проекта

Любое приложение, использующее API Google, должно включить эти API в своих настройках. API Console.

Чтобы включить API для вашего проекта:

  1. Open the API Library в Google API Console.
  2. If prompted, select a project, or create a new one.
  3. Воспользуйтесь страницей «Библиотека» , чтобы найти и включить YouTube Data API. Найдите и включите также другие API, которые будет использовать ваше приложение.

Создать учетные данные авторизации

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

  1. Go to the Clients page.
  2. Нажмите «Создать клиента» .
  3. Выберите тип приложения: Веб-приложение .
  4. Заполните форму и нажмите «Создать» . Приложения, использующие языки и фреймворки, такие как PHP, Java, Python, Ruby и .NET, должны указывать авторизованные URI перенаправления . URI перенаправления — это конечные точки, на которые сервер OAuth 2.0 может отправлять ответы. Эти конечные точки должны соответствовать правилам проверки Google .

    Для тестирования вы можете указать URI, которые ссылаются на локальный компьютер, например, http://localhost:8080 . При этом обратите внимание, что во всех примерах в этом документе в качестве URI перенаправления используется http://localhost:8080 .

    Мы рекомендуем проектировать конечные точки аутентификации вашего приложения таким образом, чтобы оно не передавало коды авторизации другим ресурсам на странице.

После создания учетных данных загрузите файл client_secret.json из [ссылка на файл] API Console. Надежно сохраните файл в месте, доступном только вашему приложению.

Определите области доступа

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

Прежде чем приступать к внедрению авторизации OAuth 2.0, мы рекомендуем определить области доступа, к которым вашему приложению потребуются разрешения.

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

API данных YouTube версии 3 использует следующие области действия:

Объем Описание
https://www. googleapis. com/ auth/ youtube Управляйте своим аккаунтом YouTube
https://www. googleapis. com/ auth/ youtube. channel-memberships. creator Посмотрите список текущих активных участников канала, их текущий уровень и дату, когда они стали участниками.
https://www. googleapis. com/ auth/ youtube. force-ssl Просмотр, редактирование и окончательное удаление ваших видео, оценок, комментариев и субтитров на YouTube.
https://www. googleapis. com/ auth/ youtube. readonly Просмотр вашего аккаунта YouTube
https://www. googleapis. com/ auth/ youtube. upload Управляйте своими видео на YouTube
https://www. googleapis. com/ auth/ youtubepartner Просмотр и управление вашими активами и связанным с ними контентом на YouTube
https://www. googleapis. com/ auth/ youtubepartner-channel-audit Просмотр конфиденциальной информации вашего канала YouTube, актуальной во время процесса аудита с партнером YouTube

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

Требования, специфичные для конкретного языка

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

PHP

Для запуска примеров PHP-кода, приведенных в этом документе, вам потребуется:

  • PHP 8.0 или более поздней версии с установленным интерфейсом командной строки (CLI) и расширением JSON.
  • Инструмент управления зависимостями Composer .
  • Клиентская библиотека Google API для PHP:

    composer require google/apiclient:^2.15.0

Дополнительную информацию см. в клиентской библиотеке Google API для PHP .

Python

Для запуска примеров кода на Python, приведенных в этом документе, вам потребуется:

  • Python 3.7 или выше
  • Инструмент управления пакетами pip .
  • Выпуск клиентской библиотеки Google API для Python 2.0:
    pip install --upgrade google-api-python-client
  • Для авторизации пользователей используются библиотеки google-auth , google-auth-oauthlib и google-auth-httplib2 .
    pip install --upgrade google-auth google-auth-oauthlib google-auth-httplib2
  • Фреймворк Flask для веб-приложений на Python.
    pip install --upgrade flask
  • Библиотека HTTP requests .
    pip install --upgrade requests

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

Руби

Для запуска примеров кода на Ruby, представленных в этом документе, вам потребуется:

  • Ruby 2.6 или выше
  • Библиотека аутентификации Google для Ruby:

    gem install googleauth
  • Веб-фреймворк Sinatra Ruby.

    gem install sinatra

Node.js

Для запуска примеров кода Node.js, приведенных в этом документе, вам потребуется:

  • Обновленная версия Node.js с поддержкой LTS, активная версия LTS или текущая версия.
  • Клиент Google API на Node.js:

    npm install googleapis crypto express express-session

HTTP/REST

Для прямого вызова конечных точек OAuth 2.0 вам не потребуется устанавливать какие-либо библиотеки.

Получение токенов доступа OAuth 2.0

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

Ниже приведён краткий обзор этих шагов:

  1. Ваше приложение определяет необходимые ему разрешения.
  2. Ваше приложение перенаправляет пользователя на сайт Google вместе со списком запрошенных разрешений.
  3. Пользователь сам решает, предоставлять ли вашему приложению необходимые разрешения.
  4. Ваше приложение выясняет, какое решение принял пользователь.
  5. Если пользователь предоставил запрошенные разрешения, ваше приложение получит токены, необходимые для выполнения API-запросов от имени пользователя.

Шаг 1: Настройка параметров авторизации

Первым шагом является создание запроса на авторизацию. Этот запрос устанавливает параметры, которые идентифицируют ваше приложение и определяют разрешения, которые пользователю будет предложено предоставить вашему приложению.

  • Если вы используете клиентскую библиотеку Google для аутентификации и авторизации OAuth 2.0, вам необходимо создать и настроить объект, определяющий эти параметры.
  • Если вы напрямую обратитесь к конечной точке Google OAuth 2.0, вы сгенерируете URL-адрес и зададите параметры для этого URL-адреса.

Приведенные ниже вкладки определяют поддерживаемые параметры авторизации для веб-серверных приложений. Примеры для конкретных языков также показывают, как использовать клиентскую библиотеку или библиотеку авторизации для настройки объекта, который устанавливает эти параметры.

PHP

Приведённый ниже фрагмент кода создаёт объект Google\Client() , который определяет параметры в запросе авторизации.

Этот объект использует информацию из файла client_secret.json для идентификации вашего приложения. (Подробнее об этом файле см. в разделе «Создание учетных данных для авторизации» .) Объект также определяет области доступа, к которым ваше приложение запрашивает разрешение, и URL-адрес конечной точки аутентификации вашего приложения, которая будет обрабатывать ответ от сервера Google OAuth 2.0. Наконец, код устанавливает необязательные параметры access_type и include_granted_scopes .

Например, этот код запрашивает доступ в автономном режиме для управления учетной записью пользователя на YouTube:

use Google\Client;

$client = new Client();

// Required, call the setAuthConfig function to load authorization credentials from
// client_secret.json file.
$client->setAuthConfig('client_secret.json');

// Required, to set the scope value, call the addScope function
$client->addScope(GOOGLE_SERVICE_YOUTUBE::YOUTUBE_FORCE_SSL);

// Required, call the setRedirectUri function to specify a valid redirect URI for the
// provided client_id
$client->setRedirectUri('http://' . $_SERVER['HTTP_HOST'] . '/oauth2callback.php');

// Recommended, offline access will give you both an access and refresh token so that
// your app can refresh the access token without user interaction.
$client->setAccessType('offline');

// Recommended, call the setState function. Using a state value can increase your assurance that
// an incoming connection is the result of an authentication request.
$client->setState($sample_passthrough_value);

// Optional, if your application knows which user is trying to authenticate, it can use this
// parameter to provide a hint to the Google Authentication Server.
$client->setLoginHint('hint@example.com');

// Optional, call the setPrompt function to set "consent" will prompt the user for consent
$client->setPrompt('consent');

// Optional, call the setIncludeGrantedScopes function with true to enable incremental
// authorization
$client->setIncludeGrantedScopes(true);

Python

Приведённый ниже фрагмент кода использует модуль google-auth-oauthlib.flow для формирования запроса на авторизацию.

Код создает объект Flow , который идентифицирует ваше приложение, используя информацию из файла client_secret.json , который вы загрузили после создания учетных данных авторизации . Этот объект также определяет области доступа, к которым ваше приложение запрашивает разрешение, и URL-адрес конечной точки аутентификации вашего приложения, которая будет обрабатывать ответ от сервера Google OAuth 2.0. Наконец, код устанавливает необязательные параметры access_type и include_granted_scopes .

Например, этот код запрашивает доступ в автономном режиме для управления учетной записью пользователя на YouTube:

import google.oauth2.credentials
import google_auth_oauthlib.flow

# Required, call the from_client_secrets_file method to retrieve the client ID from a
# client_secret.json file. The client ID (from that file) and access scopes are required. (You can
# also use the from_client_config method, which passes the client configuration as it originally
# appeared in a client secrets file but doesn't access the file itself.)
flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file('client_secret.json',
    scopes=['https://www.googleapis.com/auth/youtube.force-ssl'])

# Required, indicate where the API server will redirect the user after the user completes
# the authorization flow. The redirect URI is required. The value must exactly
# match one of the authorized redirect URIs for the OAuth 2.0 client, which you
# configured in the API Console. If this value doesn't match an authorized URI,
# you will get a 'redirect_uri_mismatch' error.
flow.redirect_uri = 'https://www.example.com/oauth2callback'

# Generate URL for request to Google's OAuth 2.0 server.
# Use kwargs to set optional request parameters.
authorization_url, state = flow.authorization_url(
    # Recommended, enable offline access so that you can refresh an access token without
    # re-prompting the user for permission. Recommended for web server apps.
    access_type='offline',
    # Optional, enable incremental authorization. Recommended as a best practice.
    include_granted_scopes='true',
    # Optional, if your application knows which user is trying to authenticate, it can use this
    # parameter to provide a hint to the Google Authentication Server.
    login_hint='hint@example.com',
    # Optional, set prompt to 'consent' will prompt the user for consent
    prompt='consent')

Руби

Используйте созданный вами файл client_secrets.json для настройки объекта клиента в вашем приложении. При настройке объекта клиента вы указываете области действия, к которым должно иметь доступ ваше приложение, а также URL-адрес конечной точки аутентификации вашего приложения, которая будет обрабатывать ответ от сервера OAuth 2.0.

Например, этот код запрашивает доступ в автономном режиме для управления учетной записью пользователя на YouTube:

require 'googleauth'
require 'googleauth/web_user_authorizer'
require 'googleauth/stores/redis_token_store'

require 'google/apis/youtube_v3'

# Required, call the from_file method to retrieve the client ID from a
# client_secret.json file.
client_id = Google::Auth::ClientId.from_file('/path/to/client_secret.json')

# Required, scope value 
scope = 'https://www.googleapis.com/auth/youtube.force-ssl'

# Required, Authorizers require a storage instance to manage long term persistence of
# access and refresh tokens.
token_store = Google::Auth::Stores::RedisTokenStore.new(redis: Redis.new)

# Required, indicate where the API server will redirect the user after the user completes
# the authorization flow. The redirect URI is required. The value must exactly
# match one of the authorized redirect URIs for the OAuth 2.0 client, which you
# configured in the API Console. If this value doesn't match an authorized URI,
# you will get a 'redirect_uri_mismatch' error.
callback_uri = '/oauth2callback'

# To use OAuth2 authentication, we need access to a CLIENT_ID, CLIENT_SECRET, AND REDIRECT_URI
# from the client_secret.json file. To get these credentials for your application, visit
# https://console.cloud.google.com/apis/credentials.
authorizer = Google::Auth::WebUserAuthorizer.new(client_id, scope,
                                                token_store, callback_uri)

Ваше приложение использует объект клиента для выполнения операций OAuth 2.0, таких как генерация URL-адресов запросов авторизации и применение токенов доступа к HTTP-запросам.

Node.js

Приведенный ниже фрагмент кода создает объект google.auth.OAuth2 , который определяет параметры в запросе авторизации.

Этот объект использует информацию из файла client_secret.json для идентификации вашего приложения. Чтобы запросить у пользователя разрешение на получение токена доступа, вы перенаправляете его на страницу согласия. Чтобы создать URL-адрес страницы согласия:

const {google} = require('googleapis');
const crypto = require('crypto');
const express = require('express');
const session = require('express-session');

/**
 * To use OAuth2 authentication, we need access to a CLIENT_ID, CLIENT_SECRET, AND REDIRECT_URI
 * from the client_secret.json file. To get these credentials for your application, visit
 * https://console.cloud.google.com/apis/credentials.
 */
const oauth2Client = new google.auth.OAuth2(
  YOUR_CLIENT_ID,
  YOUR_CLIENT_SECRET,
  YOUR_REDIRECT_URL
);

// Access scopes for YouTube API
const scopes = [
  'https://www.googleapis.com/auth/youtube.force-ssl'
];

// Generate a secure random state value.
const state = crypto.randomBytes(32).toString('hex');

// Store state in the session
req.session.state = state;

// Generate a url that asks permissions for the Drive activity and Google Calendar scope
const authorizationUrl = oauth2Client.generateAuthUrl({
  // 'online' (default) or 'offline' (gets refresh_token)
  access_type: 'offline',
  /** Pass in the scopes array defined above.
    * Alternatively, if only one scope is needed, you can pass a scope URL as a string */
  scope: scopes,
  // Enable incremental authorization. Recommended as a best practice.
  include_granted_scopes: true,
  // Include the state parameter to reduce the risk of CSRF attacks.
  state: state
});

Важное примечание : refresh_token возвращается только при первой авторизации. Подробнее здесь .

HTTP/REST

Конечная точка OAuth 2.0 от Google находится по адресу https://accounts.google.com/o/oauth2/v2/auth . Доступ к этой конечной точке возможен только по протоколу HTTPS. Простые HTTP-соединения отклоняются.

Сервер авторизации Google поддерживает следующие параметры строки запроса для веб-приложений:

Параметры
client_id Необходимый

Идентификатор клиента вашего приложения. Это значение можно найти в Cloud ConsoleClients page.

redirect_uri Необходимый

Определяет, куда API-сервер перенаправляет пользователя после завершения авторизации. Значение должно точно совпадать с одним из разрешенных URI перенаправления для клиента OAuth 2.0, который вы настроили в настройках вашего клиента. Cloud ConsoleClients pageЕсли это значение не соответствует авторизованному URI перенаправления для указанного client_id , вы получите ошибку redirect_uri_mismatch .

Обратите внимание, что схема http или https , регистр и завершающая косая черта (' / ') должны совпадать.

response_type Необходимый

Определяет, возвращает ли конечная точка Google OAuth 2.0 код авторизации.

Установите значение параметра равным " code для приложений веб-сервера.

scope Необходимый

Разделённый пробелами список областей действия, определяющих ресурсы, к которым ваше приложение может получить доступ от имени пользователя. Эти значения используются для формирования экрана согласия, который Google отображает пользователю.

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

API данных YouTube версии 3 использует следующие области действия:

Объем Описание
https://www. googleapis. com/ auth/ youtube Управляйте своим аккаунтом YouTube
https://www. googleapis. com/ auth/ youtube. channel-memberships. creator Посмотрите список текущих активных участников канала, их текущий уровень и дату, когда они стали участниками.
https://www. googleapis. com/ auth/ youtube. force-ssl Просмотр, редактирование и окончательное удаление ваших видео, оценок, комментариев и субтитров на YouTube.
https://www. googleapis. com/ auth/ youtube. readonly Просмотр вашего аккаунта YouTube
https://www. googleapis. com/ auth/ youtube. upload Управляйте своими видео на YouTube
https://www. googleapis. com/ auth/ youtubepartner Просмотр и управление вашими активами и связанным с ними контентом на YouTube
https://www. googleapis. com/ auth/ youtubepartner-channel-audit Просмотр конфиденциальной информации вашего канала YouTube, актуальной во время процесса аудита с партнером YouTube

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

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

access_type Рекомендуется

Указывает, может ли ваше приложение обновлять токены доступа, когда пользователь отсутствует в браузере. Допустимые значения параметра: online (значение по умолчанию) и offline .

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

state Рекомендуется

Указывает любое строковое значение, которое ваше приложение использует для поддержания состояния между вашим запросом на авторизацию и ответом сервера авторизации. Сервер возвращает точное значение, которое вы отправляете в виде пары name=value в компоненте запроса URL ( ? ) параметра redirect_uri после того, как пользователь дает согласие или отклоняет запрос на доступ вашего приложения.

Этот параметр можно использовать для различных целей, например, для перенаправления пользователя на правильный ресурс в вашем приложении, отправки одноразовых чисел (nonce) и предотвращения подделки межсайтовых запросов (CSS). Поскольку ваш redirect_uri может быть угадан, использование значения state может повысить вашу уверенность в том, что входящее соединение является результатом запроса аутентификации. Если вы сгенерируете случайную строку или закодируете хеш cookie или другое значение, которое отражает состояние клиента, вы можете проверить ответ, чтобы дополнительно убедиться, что запрос и ответ были отправлены из одного и того же браузера, обеспечивая защиту от таких атак, как подделка межсайтовых запросов . Пример создания и подтверждения токена state см. в документации OpenID Connect.

include_granted_scopes Необязательный

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

login_hint Необязательный

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

Установите значение параметра равным адресу электронной почты или sub , эквивалентному идентификатору пользователя в Google.

prompt Необязательный

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

Возможные значения:

none Не отображать экраны аутентификации или согласия. Не должно указываться с другими значениями.
consent Запросите у пользователя согласие.
select_account Предложите пользователю выбрать учетную запись.

Шаг 2: Перенаправление на сервер Google OAuth 2.0

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

PHP

  1. Сгенерируйте URL-адрес для запроса доступа к серверу OAuth 2.0 от Google:
    $auth_url = $client->createAuthUrl();
  2. Перенаправить пользователя на $auth_url :
    header('Location: ' . filter_var($auth_url, FILTER_SANITIZE_URL));

Python

В этом примере показано, как перенаправить пользователя на URL-адрес авторизации с помощью веб-фреймворка Flask:

return flask.redirect(authorization_url)

Руби

  1. Сгенерируйте URL-адрес для запроса доступа к серверу OAuth 2.0 от Google:
    auth_uri = authorizer.get_authorization_url(request: request)
  2. Перенаправьте пользователя на auth_uri .

Node.js

  1. Используйте сгенерированный URL-адрес authorizationUrl из шага 1 , полученный с помощью метода generateAuthUrl , для запроса доступа к серверу OAuth 2.0 от Google.
  2. Перенаправьте пользователя на authorizationUrl .
    res.redirect(authorizationUrl);

HTTP/REST

Пример перенаправления на сервер авторизации Google.

Приведённый ниже пример URL-адреса запрашивает автономный доступ ( access_type=offline ) к области действия, разрешающей просмотр учётной записи пользователя на YouTube. Он использует инкрементальную авторизацию, чтобы гарантировать, что новый токен доступа охватывает все области действия, к которым пользователь ранее предоставил приложению доступ. URL-адрес также устанавливает значения для обязательных параметров redirect_uri , response_type и client_id , а также для параметра state . URL-адрес содержит переносы строк и пробелы для удобства чтения.

https://accounts.google.com/o/oauth2/v2/auth?
 scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fyoutube.readonly&
 access_type=offline&
 include_granted_scopes=true&
 state=state_parameter_passthrough_value&
 redirect_uri=http%3A%2F%2Flocalhost%2Foauth2callback&
 response_type=code&
 client_id=client_id

После создания URL-адреса запроса перенаправьте пользователя на него.

Сервер OAuth 2.0 от Google аутентифицирует пользователя и получает от него согласие на доступ вашего приложения к запрошенным областям действия. Ответ отправляется обратно в ваше приложение с использованием указанного вами URL-адреса перенаправления.

Шаг 3: Google запрашивает у пользователя согласие.

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

На данном этапе вашему приложению не нужно ничего делать, поскольку оно ожидает ответа от сервера OAuth 2.0 от Google, указывающего, был ли предоставлен доступ. Этот ответ объясняется на следующем шаге.

Ошибки

При обращении к конечной точке авторизации OAuth 2.0 от Google вместо ожидаемых процессов аутентификации и авторизации могут отображаться сообщения об ошибках, предназначенные для пользователя. Распространенные коды ошибок и рекомендуемые способы их устранения:

admin_policy_enforced

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

disallowed_useragent

Точка авторизации отображается внутри встроенного пользовательского агента, что запрещено политикой Google OAuth 2.0 .

Разработчики iOS и macOS могут столкнуться с этой ошибкой при открытии запросов авторизации в WKWebView . Вместо этого разработчикам следует использовать библиотеки iOS, такие как Google Sign-In для iOS или AppAuth для iOS от OpenID Foundation.

Веб-разработчики могут столкнуться с этой ошибкой, когда приложение для iOS или macOS открывает обычную веб-ссылку во встроенном пользовательском агенте, и пользователь переходит на конечную точку авторизации Google OAuth 2.0 с вашего сайта. Разработчикам следует разрешить открытие обычных ссылок в обработчике ссылок по умолчанию операционной системы, включая обработчики универсальных ссылок или обработчики ссылок браузера по умолчанию. Библиотека SFSafariViewController также является поддерживаемым вариантом.

org_internal

Идентификатор клиента OAuth в запросе является частью проекта, ограничивающего доступ к учетным записям Google в конкретной организации Google Cloud . Для получения дополнительной информации об этом параметре конфигурации см. раздел «Тип пользователя» в справочной статье «Настройка экрана согласия OAuth».

invalid_client

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

deleted_client

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

invalid_grant

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

redirect_uri_mismatch

Передаваемый в запросе авторизации параметр redirect_uri не соответствует разрешенному URI перенаправления для идентификатора клиента OAuth. Проверьте разрешенные URI перенаправления в... Google Cloud ConsoleClients page.

Параметр redirect_uri может указывать на устаревший и больше не поддерживаемый поток OAuth out-of-band (OOB). Для обновления интеграции обратитесь к руководству по миграции .

invalid_request

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

  • Запрос был оформлен неправильно.
  • В запросе отсутствовали необходимые параметры.
  • В запросе используется метод авторизации, который Google не поддерживает. Убедитесь, что ваша интеграция OAuth использует рекомендуемый метод интеграции.

Шаг 4: Обработка ответа сервера OAuth 2.0

Сервер OAuth 2.0 отвечает на запрос доступа вашего приложения, используя URL-адрес, указанный в запросе.

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

Сообщение об ошибке:

https://oauth2.example.com/auth?error=access_denied

Ответ с кодом авторизации:

https://oauth2.example.com/auth?code=4/P7q7W91a-oMsCeLvIaQm6bTrgtp7

Пример ответа сервера OAuth 2.0

Вы можете протестировать этот процесс, перейдя по следующей ссылке, которая запрашивает доступ только для чтения к просмотру метаданных файлов в вашем Google Диске и доступ только для чтения к просмотру событий вашего Календаря Google:

https://accounts.google.com/o/oauth2/v2/auth?
 scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fyoutube.readonly&
 access_type=offline&
 include_granted_scopes=true&
 state=state_parameter_passthrough_value&
 redirect_uri=http%3A%2F%2Flocalhost%2Foauth2callback&
 response_type=code&
 client_id=client_id

После завершения процесса OAuth 2.0 ваш браузер перенаправит вас на OAuth 2.0 Playground — инструмент для тестирования процессов OAuth. Вы увидите, что OAuth 2.0 Playground автоматически получил код авторизации.

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

После получения кода авторизации веб-сервер может обменять этот код на токен доступа.

PHP

Для обмена кода авторизации на токен доступа используйте метод fetchAccessTokenWithAuthCode :

$access_token = $client->fetchAccessTokenWithAuthCode($_GET['code']);

Python

На странице обратного вызова используйте библиотеку google-auth для проверки ответа сервера авторизации. Затем используйте метод flow.fetch_token для обмена кода авторизации из этого ответа на токен доступа:

state = flask.session['state']
flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
    'client_secret.json',
    scopes=['https://www.googleapis.com/auth/youtube.force-ssl'],
    state=state)
flow.redirect_uri = flask.url_for('oauth2callback', _external=True)

authorization_response = flask.request.url
flow.fetch_token(authorization_response=authorization_response)

# Store the credentials in browser session storage, but for security: client_id, client_secret,
# and token_uri are instead stored only on the backend server.
credentials = flow.credentials
flask.session['credentials'] = {
    'token': credentials.token,
    'refresh_token': credentials.refresh_token,
    'granted_scopes': credentials.granted_scopes}

Руби

На странице обратного вызова используйте библиотеку googleauth для проверки ответа сервера авторизации. Используйте метод authorizer.handle_auth_callback_deferred , чтобы сохранить код авторизации и перенаправить пользователя обратно на URL-адрес, который изначально запрашивал авторизацию. Это откладывает обмен кодом, временно сохраняя результаты в сессии пользователя.

  target_url = Google::Auth::WebUserAuthorizer.handle_auth_callback_deferred(request)
  redirect target_url

Node.js

Для обмена кода авторизации на токен доступа используйте метод getToken :

const url = require('url');

// Receive the callback from Google's OAuth 2.0 server.
app.get('/oauth2callback', async (req, res) => {
  let q = url.parse(req.url, true).query;

  if (q.error) { // An error response e.g. error=access_denied
    console.log('Error:' + q.error);
  } else if (q.state !== req.session.state) { //check state value
    console.log('State mismatch. Possible CSRF attack');
    res.end('State mismatch. Possible CSRF attack');
  } else { // Get access and refresh tokens (if access_type is offline)

    let { tokens } = await oauth2Client.getToken(q.code);
    oauth2Client.setCredentials(tokens);
});

HTTP/REST

Для обмена кода авторизации на токен доступа вызовите конечную точку https://oauth2.googleapis.com/token и установите следующие параметры:

Поля
client_id Идентификатор клиента, полученный из Cloud ConsoleClients page.
client_secret Необязательный

Секрет клиента получен из Cloud ConsoleClients page.

code Код авторизации, полученный в результате первоначального запроса.
grant_type В соответствии со спецификацией OAuth 2.0 , значение этого поля должно быть установлено на authorization_code .
redirect_uri Один из URI перенаправления, указанных для вашего проекта в Cloud ConsoleClients page для указанного client_id .

Следующий фрагмент кода демонстрирует пример запроса:

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

code=4/P7q7W91a-oMsCeLvIaQm6bTrgtp7&
client_id=your_client_id&
redirect_uri=https%3A//developers.google.com/oauthplayground&
grant_type=authorization_code

В ответ на этот запрос Google возвращает JSON-объект, содержащий кратковременный токен доступа и токен обновления. Обратите внимание, что токен обновления возвращается только в том случае, если ваше приложение установило параметр access_type в offline в первоначальном запросе к серверу авторизации Google .

Ответ содержит следующие поля:

Поля
access_token Токен, который ваше приложение отправляет для авторизации запроса к API Google.
expires_in Оставшийся срок действия токена доступа в секундах.
refresh_token Токен, который можно использовать для получения нового токена доступа. Токены обновления действительны до тех пор, пока пользователь не отзовет доступ или пока срок действия токена обновления не истечет. Еще раз подчеркнем, что это поле присутствует в этом ответе только в том случае, если вы установили параметр access_type в offline в первоначальном запросе к серверу авторизации Google.
refresh_token_expires_in Оставшийся срок действия токена обновления в секундах. Это значение устанавливается только в том случае, если пользователь предоставляет доступ по времени .
scope Области доступа, предоставляемые access_token выражены в виде списка строк, разделенных пробелами и чувствительных к регистру.
token_type Тип возвращаемого токена. В настоящее время значение этого поля всегда равно Bearer .

Следующий фрагмент кода демонстрирует пример ответа:

{
  "access_token": "1/fFAGRNJru1FTz70BzhT3Zg",
  "expires_in": 3920,
  "token_type": "Bearer",
  "scope": "https://www.googleapis.com/auth/youtube.force-ssl",
  "refresh_token": "1//xEoDL4iW3cxlI7yDbSRFYNG01kVKM2C-259HOF2aQbI"
}

Ошибки

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

invalid_grant

Предоставленный код авторизации недействителен или имеет неправильный формат. Запросите новый код, перезапустив процесс OAuth , чтобы снова запросить у пользователя подтверждение.

Шаг 6: Проверьте, какие права доступа были предоставлены пользователям.

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

Однако есть исключения. Приложения Google Workspace Enterprise с делегированием полномочий на уровне домена или приложения, помеченные как «Доверенные» , обходят экран подтверждения согласия на предоставление детальных разрешений. Для таких приложений пользователи не увидят экран подтверждения согласия на предоставление детальных разрешений. Вместо этого ваше приложение получит либо все запрошенные области действия, либо ни одной.

Более подробную информацию см. в разделе «Как управлять детализированными правами доступа» .

PHP

Чтобы проверить, какие права доступа предоставил пользователь, используйте метод getGrantedScope() :

// Space-separated string of granted scopes if it exists, otherwise null.
$granted_scopes = $client->getOAuth2Service()->getGrantedScope();

Python

Возвращаемый объект credentials имеет свойство granted_scopes , которое представляет собой список областей действия, предоставленных пользователем вашему приложению.

credentials = flow.credentials
flask.session['credentials'] = {
    'token': credentials.token,
    'refresh_token': credentials.refresh_token,
    'granted_scopes': credentials.granted_scopes}

Руби

При запросе нескольких областей действия одновременно проверьте, какие области действия были предоставлены через свойство scope объекта credentials .

# User authorized the request. Now, check which scopes were granted.
if credentials.scope.include?(Google::Apis::YoutubeV3::AUTH_YOUTUBE_FORCE_SSL)
  # User authorized permission to see, edit, and permanently delete the
  # YouTube videos, ratings, comments and captions.
  # Calling the APIs, etc
else
  # User didn't authorize the permission.
  # Update UX and application accordingly
end

Node.js

При запросе нескольких областей действия одновременно проверьте, какие области действия были предоставлены, используя свойство scope объекта tokens .

// User authorized the request. Now, check which scopes were granted.
if (tokens.scope.includes('https://www.googleapis.com/auth/youtube.force-ssl'))
{
  // User authorized permission to see, edit, and permanently delete the
  // YouTube videos, ratings, comments and captions.
  // Calling the APIs, etc.
}
else
{
  // User didn't authorize read-only Drive activity permission.
  // Update UX and application accordingly
}

HTTP/REST

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

Например, следующий пример ответа в виде токена доступа указывает на то, что пользователь предоставил вашему приложению разрешение на просмотр, редактирование и безвозвратное удаление видео, оценок, комментариев и подписей пользователя на YouTube:

  {
    "access_token": "1/fFAGRNJru1FTz70BzhT3Zg",
    "expires_in": 3920,
    "token_type": "Bearer",
    "scope": "https://www.googleapis.com/auth/youtube.force-ssl",
    "refresh_token": "1//xEoDL4iW3cxlI7yDbSRFYNG01kVKM2C-259HOF2aQbI"
  }

Вызов API Google

PHP

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

  1. Если вам необходимо применить токен доступа к новому объекту Google\Client — например, если вы сохранили токен доступа в пользовательской сессии — используйте метод setAccessToken :
    $client->setAccessToken($access_token);
  2. Создайте объект сервиса для API, который вы хотите вызвать. Для этого предоставьте в конструктор API авторизованный объект Google\Client . Например, для вызова YouTube Data API:
    $youtube = new Google_Service_YouTube($client);
  3. Отправляйте запросы к API-сервису, используя интерфейс, предоставляемый объектом сервиса . Например, чтобы получить данные о YouTube-канале авторизованного пользователя:
    $channel = $youtube->channels->listChannels('snippet', array('mine' => $mine));

Python

После получения токена доступа ваше приложение может использовать его для авторизации запросов к API от имени определенной учетной записи пользователя или сервисной учетной записи. Используйте учетные данные авторизации, специфичные для пользователя, для создания сервисного объекта для API, который вы хотите вызвать, а затем используйте этот объект для выполнения авторизованных запросов к API.

  1. Создайте объект сервиса для API, к которому вы хотите обратиться. Для этого вызовите метод build библиотеки ` googleapiclient.discovery , указав имя и версию API, а также учетные данные пользователя: Например, для вызова версии 3 API данных YouTube:
    from googleapiclient.discovery import build
    
    youtube = build('youtube', 'v3', credentials=credentials)
  2. Отправляйте запросы к API-сервису, используя интерфейс, предоставляемый объектом сервиса . Например, чтобы получить данные о YouTube-канале авторизованного пользователя:
    channel = youtube.channels().list(mine=True, part='snippet').execute()

Руби

После получения токена доступа ваше приложение может использовать его для выполнения запросов к API от имени определенной учетной записи пользователя или сервисной учетной записи. Используйте учетные данные авторизации, специфичные для пользователя, для создания объекта сервиса для API, который вы хотите вызвать, а затем используйте этот объект для выполнения авторизованных запросов к API.

  1. Создайте объект сервиса для API, к которому вы хотите обратиться. Например, для вызова версии 3 YouTube Data API:
    youtube = Google::Apis::YoutubeV3::YouTubeService.new
  2. Укажите учетные данные для службы:
    youtube.authorization = credentials
  3. Отправляйте запросы к API-сервису, используя интерфейс, предоставляемый объектом сервиса . Например, чтобы получить данные о YouTube-канале авторизованного пользователя:
    channel = youtube.list_channels(part, :mine => mine)

В качестве альтернативы, авторизацию можно предоставлять для каждого метода отдельно, передав параметр options методу:

channel = youtube.list_channels(part, :mine => mine, options: { authorization: auth_client })

Node.js

После получения токена доступа и присвоения его объекту OAuth2 используйте этот объект для вызова API Google. Ваше приложение может использовать этот токен для авторизации запросов API от имени определенной учетной записи пользователя или сервисной учетной записи. Создайте сервисный объект для API, который вы хотите вызвать. Например, следующий код использует API Google Drive для отображения имен файлов в Google Диске пользователя.

const { google } = require('googleapis');

// Example of using YouTube API to list channels.
var service = google.youtube('v3');
service.channels.list({
  auth: oauth2Client,
  part: 'snippet,contentDetails,statistics',
  forUsername: 'GoogleDevelopers'
}, function (err, response) {
  if (err) {
    console.log('The API returned an error: ' + err);
    return;
  }
  var channels = response.data.items;
  if (channels.length == 0) {
    console.log('No channel found.');
  } else {
    console.log('This channel\'s ID is %s. Its title is \'%s\', and ' +
      'it has %s views.',
      channels[0].id,
      channels[0].snippet.title,
      channels[0].statistics.viewCount);
  }
});

HTTP/REST

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

Обратите внимание, что API данных YouTube поддерживает сервисные учетные записи только для владельцев контента YouTube, которые владеют и управляют несколькими каналами YouTube, например, звукозаписывающие компании и киностудии.

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

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

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

GET /youtube/v3/channels?part=snippet&mine=true HTTP/1.1
Host: www.googleapis.com
Authorization: Bearer access_token

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

GET https://www.googleapis.com/youtube/v3/channels?access_token=access_token&part=snippet&mine=true

примеры curl

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

curl -H "Authorization: Bearer access_token" https://www.googleapis.com/youtube/v3/channels?part=snippet&mine=true

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

curl https://www.googleapis.com/youtube/v3/channels?access_token=access_token&part=snippet&mine=true

Полный пример

В следующем примере отображается объект в формате JSON, показывающий информацию о канале пользователя на YouTube после того, как пользователь аутентифицируется и авторизует приложение для управления своей учетной записью YouTube.

PHP

Чтобы запустить этот пример:

  1. В API ConsoleДобавьте URL локального компьютера в список URL-адресов перенаправления. Например, добавьте http://localhost:8080 .
  2. Создайте новую директорию и перейдите в неё. Например:
    mkdir ~/php-oauth2-example
    cd ~/php-oauth2-example
  3. Установите клиентскую библиотеку Google API для PHP с помощью Composer :
    composer require google/apiclient:^2.15.0
  4. Создайте файлы index.php и oauth2callback.php со следующим содержимым.
  5. Запустите пример, используя встроенный в PHP тестовый веб-сервер:
    php -S localhost:8080 ~/php-oauth2-example

index.php

<?php
require_once __DIR__.'/vendor/autoload.php';

session_start();

$client = new Google\Client();
$client->setAuthConfig('client_secret.json');

// User granted permission as an access token is in the session.
if (isset($_SESSION['access_token']) && $_SESSION['access_token'])
{
  $client->setAccessToken($_SESSION['access_token']);
  
  $youtube = new Google_Service_YouTube($client);
  $channel = $youtube->channels->listChannels('snippet', array('mine' => $mine));
  echo json_encode($channel);
  
}
else
{
  // Redirect users to outh2call.php which redirects users to Google OAuth 2.0
  $redirect_uri = 'http://' . $_SERVER['HTTP_HOST'] . '/oauth2callback.php';
  header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL));
}
?>

oauth2callback.php

<?php
require_once __DIR__.'/vendor/autoload.php';

session_start();

$client = new Google\Client();

// Required, call the setAuthConfig function to load authorization credentials from
// client_secret.json file.
$client->setAuthConfigFile('client_secret.json');
$client->setRedirectUri('http://' . $_SERVER['HTTP_HOST']. $_SERVER['PHP_SELF']);

// Required, to set the scope value, call the addScope function.
$client->addScope(GOOGLE_SERVICE_YOUTUBE::YOUTUBE_FORCE_SSL);

// Enable incremental authorization. Recommended as a best practice.
$client->setIncludeGrantedScopes(true);

// Recommended, offline access will give you both an access and refresh token so that
// your app can refresh the access token without user interaction.
$client->setAccessType("offline");

// Generate a URL for authorization as it doesn't contain code and error
if (!isset($_GET['code']) && !isset($_GET['error']))
{
  // Generate and set state value
  $state = bin2hex(random_bytes(16));
  $client->setState($state);
  $_SESSION['state'] = $state;

  // Generate a url that asks permissions.
  $auth_url = $client->createAuthUrl();
  header('Location: ' . filter_var($auth_url, FILTER_SANITIZE_URL));
}

// User authorized the request and authorization code is returned to exchange access and
// refresh tokens.
if (isset($_GET['code']))
{
  // Check the state value
  if (!isset($_GET['state']) || $_GET['state'] !== $_SESSION['state']) {
    die('State mismatch. Possible CSRF attack.');
  }

  // Get access and refresh tokens (if access_type is offline)
  $token = $client->fetchAccessTokenWithAuthCode($_GET['code']);

  /** Save access and refresh token to the session variables.
    * ACTION ITEM: In a production app, you likely want to save the
    *              refresh token in a secure persistent storage instead. */
  $_SESSION['access_token'] = $token;
  $_SESSION['refresh_token'] = $client->getRefreshToken();
  
  $redirect_uri = 'http://' . $_SERVER['HTTP_HOST'] . '/';
  header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL));
}

// An error response e.g. error=access_denied
if (isset($_GET['error']))
{
  echo "Error: ". $_GET['error'];
}
?>

Python

В этом примере используется фреймворк Flask . Он запускает веб-приложение по http://localhost:8080 , которое позволяет протестировать поток OAuth 2.0. Если вы перейдете по этому URL, вы увидите пять ссылок:

  • Проверка API-запроса: Эта ссылка ведет на страницу, которая пытается выполнить примерный API-запрос. При необходимости запускается процесс авторизации. В случае успеха страница отображает ответ API.
  • Проверьте процесс аутентификации напрямую: эта ссылка ведет на страницу, которая пытается перенаправить пользователя через процесс авторизации . Приложение запрашивает разрешение на отправку авторизованных API-запросов от имени пользователя.
  • Отозвать текущие учетные данные: Эта ссылка ведет на страницу, которая отзывает разрешения, уже предоставленные пользователем приложению.
  • Очистка учетных данных сессии Flask: Эта ссылка очищает учетные данные авторизации, хранящиеся в сессии Flask. Это позволяет увидеть, что произойдет, если пользователь, уже предоставивший вашему приложению разрешение, попытается выполнить запрос к API в новой сессии. Это также позволяет увидеть ответ API, который получит ваше приложение, если пользователь отозвал предоставленные вашему приложению разрешения, а ваше приложение все еще попытается авторизовать запрос с отозванным токеном доступа.
# -*- coding: utf-8 -*-

import os
import flask
import json
import requests

import google.oauth2.credentials
import google_auth_oauthlib.flow
import googleapiclient.discovery

# This variable specifies the name of a file that contains the OAuth 2.0
# information for this application, including its client_id and client_secret.
CLIENT_SECRETS_FILE = "client_secret.json"

# The OAuth 2.0 access scope allows for access to the
# authenticated user's account and requires requests to use an SSL connection.
SCOPES = ['https://www.googleapis.com/auth/youtube.force-ssl']
API_SERVICE_NAME = 'youtube'
API_VERSION = 'v3'

app = flask.Flask(__name__)
# Note: A secret key is included in the sample so that it works.
# If you use this code in your application, replace this with a truly secret
# key. See https://flask.palletsprojects.com/quickstart/#sessions.
app.secret_key = 'REPLACE ME - this value is here as a placeholder.'

@app.route('/')
def index():
  return print_index_table()

@app.route('/test')
def test_api_request():
  if 'credentials' not in flask.session:
  return flask.redirect('authorize')

  # Load credentials from the session.
  credentials = google.oauth2.credentials.Credentials(
    **flask.session['credentials'])

  youtube = googleapiclient.discovery.build(
    API_SERVICE_NAME, API_VERSION, credentials=credentials)

  channel = youtube.channels().list(mine=True, part='snippet').execute()

  # Save credentials back to session in case access token was refreshed.
  # ACTION ITEM: In a production app, you likely want to save these
  #              credentials in a persistent database instead.
  flask.session['credentials'] = credentials_to_dict(credentials)

  return flask.jsonify(**channel)
@app.route('/authorize')
def authorize():
  # Create flow instance to manage the OAuth 2.0 Authorization Grant Flow steps.
  flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
      CLIENT_SECRETS_FILE, scopes=SCOPES)

  # The URI created here must exactly match one of the authorized redirect URIs
  # for the OAuth 2.0 client, which you configured in the API Console. If this
  # value doesn't match an authorized URI, you will get a 'redirect_uri_mismatch'
  # error.
  flow.redirect_uri = flask.url_for('oauth2callback', _external=True)

  authorization_url, state = flow.authorization_url(
      # Enable offline access so that you can refresh an access token without
      # re-prompting the user for permission. Recommended for web server apps.
      access_type='offline',
      # Enable incremental authorization. Recommended as a best practice.
      include_granted_scopes='true')

  # Store the state so the callback can verify the auth server response.
  flask.session['state'] = state

  return flask.redirect(authorization_url)

@app.route('/oauth2callback')
def oauth2callback():
  # Specify the state when creating the flow in the callback so that it can
  # verified in the authorization server response.
  state = flask.session['state']

  flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
      CLIENT_SECRETS_FILE, scopes=SCOPES, state=state)
  flow.redirect_uri = flask.url_for('oauth2callback', _external=True)

  # Use the authorization server's response to fetch the OAuth 2.0 tokens.
  authorization_response = flask.request.url
  flow.fetch_token(authorization_response=authorization_response)

  # Store credentials in the session.
  # ACTION ITEM: In a production app, you likely want to save these
  #              credentials in a persistent database instead.
  credentials = flow.credentials
  
  flask.session['credentials'] = credentials_to_dict(credentials)

  return flask.redirect(flask.url_for('test_api_request'))
  
@app.route('/revoke')
def revoke():
  if 'credentials' not in flask.session:
    return ('You need to <a href="/authorize">authorize</a> before ' +
            'testing the code to revoke credentials.')

  # Load client secrets from the server-side file.
  with open(CLIENT_SECRETS_FILE, 'r') as f:
      client_config = json.load(f)['web']

  # Load user-specific credentials from the session.
  session_credentials = flask.session['credentials']

  # Reconstruct the credentials object.
  credentials = google.oauth2.credentials.Credentials(
      refresh_token=session_credentials.get('refresh_token'),
      scopes=session_credentials.get('granted_scopes'),
      token=session_credentials.get('token'),
      client_id=client_config.get('client_id'),
      client_secret=client_config.get('client_secret'),
      token_uri=client_config.get('token_uri'))

  revoke = requests.post('https://oauth2.googleapis.com/revoke',
      params={'token': credentials.token},
      headers = {'content-type': 'application/x-www-form-urlencoded'})

  status_code = getattr(revoke, 'status_code')
  if status_code == 200:
    # Clear the user's session credentials after successful revocation
    if 'credentials' in flask.session:
        del flask.session['credentials']
        del flask.session['features']
    return('Credentials successfully revoked.' + print_index_table())
  else:
    return('An error occurred.' + print_index_table())

@app.route('/clear')
def clear_credentials():
  if 'credentials' in flask.session:
    del flask.session['credentials']
  return ('Credentials have been cleared.<br><br>' +
          print_index_table())

def credentials_to_dict(credentials):
  return {'token': credentials.token,
          'refresh_token': credentials.refresh_token,
          'granted_scopes': credentials.granted_scopes}

def print_index_table():
  return ('<table>' + 
          '<tr><td><a href="/test">Test an API request</a></td>' +
          '<td>Submit an API request and see a formatted JSON response. ' +
          '    Go through the authorization flow if there are no stored ' +
          '    credentials for the user.</td></tr>' + 
          '<tr><td><a href="/revoke">Revoke current credentials</a></td>' +
          '<td>Revoke the access token associated with the current user ' +
          '    session. After revoking credentials, if you go to the test ' +
          '    page, you should see an <code>invalid_grant</code> error.' +
          '</td></tr>' +
          '<tr><td><a href="/clear">Clear Flask session credentials</a></td>' +
          '<td>Clear the access token currently stored in the user session. ' +
          '    After clearing the token, if you <a href="/test">test the ' +
          '    API request</a> ' +
          '    again, you should go back to the auth flow.' +
          '</td></tr></table>')

if __name__ == '__main__':
  # When running locally, disable OAuthlib's HTTPs verification.
  # ACTION ITEM for developers:
  #     When running in production *do not* leave this option enabled.
  os.environ['OAUTHLIB_INSECURE_TRANSPORT'] = '1'

  # This disables the requested scopes and granted scopes check.
  # If users only grant partial request, the warning would not be thrown.
  os.environ['OAUTHLIB_RELAX_TOKEN_SCOPE'] = '1'

  # Specify a hostname and port that are set as a valid redirect URI
  # for your API project in the Google API Console.
  app.run('localhost', 8080, debug=True)

Руби

В этом примере используется фреймворк Sinatra .

require 'googleauth'
require 'googleauth/web_user_authorizer'
require 'googleauth/stores/redis_token_store'

require 'google/apis/youtube_v3'

require 'sinatra'

configure do
  enable :sessions

  # Required, call the from_file method to retrieve the client ID from a
  # client_secret.json file.
  set :client_id, Google::Auth::ClientId.from_file('/path/to/client_secret.json')

  # Required, scope value
  # Access scopes for retrieving data about the user's YouTube channel.
  scope = 'Google::Apis::YoutubeV3::AUTH_YOUTUBE_FORCE_SSL'

  # Required, Authorizers require a storage instance to manage long term persistence of
  # access and refresh tokens.
  set :token_store, Google::Auth::Stores::RedisTokenStore.new(redis: Redis.new)

  # Required, indicate where the API server will redirect the user after the user completes
  # the authorization flow. The redirect URI is required. The value must exactly
  # match one of the authorized redirect URIs for the OAuth 2.0 client, which you
  # configured in the API Console. If this value doesn't match an authorized URI,
  # you will get a 'redirect_uri_mismatch' error.
  set :callback_uri, '/oauth2callback'

  # To use OAuth2 authentication, we need access to a CLIENT_ID, CLIENT_SECRET, AND REDIRECT_URI
  # from the client_secret.json file. To get these credentials for your application, visit
  # https://console.cloud.google.com/apis/credentials.
  set :authorizer, Google::Auth::WebUserAuthorizer.new(settings.client_id, settings.scope,
                          settings.token_store, callback_uri: settings.callback_uri)
end

get '/' do
  # NOTE: Assumes the user is already authenticated to the app
  user_id = request.session['user_id']

  # Fetch stored credentials for the user from the given request session.
  # nil if none present
  credentials = settings.authorizer.get_credentials(user_id, request)

  if credentials.nil?
    # Generate a url that asks the user to authorize requested scope(s).
    # Then, redirect user to the url.
    redirect settings.authorizer.get_authorization_url(request: request)
  end
  
  # User authorized read-only YouTube Data API permission.
  # Example of using YouTube Data API to list user's YouTube channel
  youtube = Google::Apis::YoutubeV3::YouTubeService.new
  channel = youtube.list_channels(part, :mine => mine, options: { authorization: auth_client })
  
  "<pre>#{JSON.pretty_generate(channel.to_h)}</pre>"
end

# Receive the callback from Google's OAuth 2.0 server.
get '/oauth2callback' do
  # Handle the result of the oauth callback. Defers the exchange of the code by
  # temporarily stashing the results in the user's session.
  target_url = Google::Auth::WebUserAuthorizer.handle_auth_callback_deferred(request)
  redirect target_url
end

Node.js

Чтобы запустить этот пример:

  1. В API ConsoleДобавьте URL локального компьютера в список URL-адресов перенаправления. Например, добавьте http://localhost .
  2. Убедитесь, что у вас установлена ​​версия Node.js с поддержкой обслуживания (SMS), активная версия с поддержкой LTS или текущая версия.
  3. Создайте новую директорию и перейдите в неё. Например:
    mkdir ~/nodejs-oauth2-example
    cd ~/nodejs-oauth2-example
  4. Установите клиентскую библиотеку Google API для Node.js с помощью npm :
    npm install googleapis
  5. Создайте файл main.js со следующим содержимым.
  6. Запустите пример:
    node .\main.js

main.js

const http = require('http');
const https = require('https');
const url = require('url');
const { google } = require('googleapis');
const crypto = require('crypto');
const express = require('express');
const session = require('express-session');

/**
 * To use OAuth2 authentication, we need access to a CLIENT_ID, CLIENT_SECRET, AND REDIRECT_URI.
 * To get these credentials for your application, visit
 * https://console.cloud.google.com/apis/credentials.
 */
const oauth2Client = new google.auth.OAuth2(
  YOUR_CLIENT_ID,
  YOUR_CLIENT_SECRET,
  YOUR_REDIRECT_URL
);

// Access scopes for YouTube API
const scopes = [
  'https://www.googleapis.com/auth/youtube.force-ssl'
];

/* Global variable that stores user credential in this code example.
 * ACTION ITEM for developers:
 *   Store user's refresh token in your data store if
 *   incorporating this code into your real app.
 *   For more information on handling refresh tokens,
 *   see https://github.com/googleapis/google-api-nodejs-client#handling-refresh-tokens
 */
let userCredential = null;

async function main() {
  const app = express();

  app.use(session({
    secret: 'your_secure_secret_key', // Replace with a strong secret
    resave: false,
    saveUninitialized: false,
  }));

  // Example on redirecting user to Google's OAuth 2.0 server.
  app.get('/', async (req, res) => {
    // Generate a secure random state value.
    const state = crypto.randomBytes(32).toString('hex');
    // Store state in the session
    req.session.state = state;

    // Generate a url that asks permissions for the Drive activity and Google Calendar scope
    const authorizationUrl = oauth2Client.generateAuthUrl({
      // 'online' (default) or 'offline' (gets refresh_token)
      access_type: 'offline',
      /** Pass in the scopes array defined above.
        * Alternatively, if only one scope is needed, you can pass a scope URL as a string */
      scope: scopes,
      // Enable incremental authorization. Recommended as a best practice.
      include_granted_scopes: true,
      // Include the state parameter to reduce the risk of CSRF attacks.
      state: state
    });

    res.redirect(authorizationUrl);
  });

  // Receive the callback from Google's OAuth 2.0 server.
  app.get('/oauth2callback', async (req, res) => {
    // Handle the OAuth 2.0 server response
    let q = url.parse(req.url, true).query;

    if (q.error) { // An error response e.g. error=access_denied
      console.log('Error:' + q.error);
    } else if (q.state !== req.session.state) { //check state value
      console.log('State mismatch. Possible CSRF attack');
      res.end('State mismatch. Possible CSRF attack');
    } else { // Get access and refresh tokens (if access_type is offline)
      let { tokens } = await oauth2Client.getToken(q.code);
      oauth2Client.setCredentials(tokens);

      /** Save credential to the global variable in case access token was refreshed.
        * ACTION ITEM: In a production app, you likely want to save the refresh token
        *              in a secure persistent database instead. */
      userCredential = tokens;
      
      // Example of using YouTube API to list channels.
      var service = google.youtube('v3');
      service.channels.list({
        auth: oauth2Client,
        part: 'snippet,contentDetails,statistics',
        forUsername: 'GoogleDevelopers'
      }, function (err, response) {
        if (err) {
          console.log('The API returned an error: ' + err);
          return;
        }
        var channels = response.data.items;
        if (channels.length == 0) {
          console.log('No channel found.');
        } else {
          console.log('This channel\'s ID is %s. Its title is \'%s\', and ' +
            'it has %s views.',
            channels[0].id,
            channels[0].snippet.title,
            channels[0].statistics.viewCount);
        }
      });
    }
  });

  // Example on revoking a token
  app.get('/revoke', async (req, res) => {
    // Build the string for the POST request
    let postData = "token=" + userCredential.access_token;

    // Options for POST request to Google's OAuth 2.0 server to revoke a token
    let postOptions = {
      host: 'oauth2.googleapis.com',
      port: '443',
      path: '/revoke',
      method: 'POST',
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded',
        'Content-Length': Buffer.byteLength(postData)
      }
    };

    // Set up the request
    const postReq = https.request(postOptions, function (res) {
      res.setEncoding('utf8');
      res.on('data', d => {
        console.log('Response: ' + d);
      });
    });

    postReq.on('error', error => {
      console.log(error)
    });

    // Post the request with data
    postReq.write(postData);
    postReq.end();
  });


  const server = http.createServer(app);
  server.listen(8080);
}
main().catch(console.error);

HTTP/REST

В этом примере на Python используется фреймворк Flask и библиотека Requests для демонстрации веб-процесса OAuth 2.0. Мы рекомендуем использовать для этого процесса клиентскую библиотеку Google API для Python. (В примере на вкладке Python используется именно эта клиентская библиотека.)

import json
import flask
import requests

app = flask.Flask(__name__)

# To get these credentials (CLIENT_ID CLIENT_SECRET) and for your application, visit
# https://console.cloud.google.com/apis/credentials.
CLIENT_ID = '123456789.apps.googleusercontent.com'
CLIENT_SECRET = 'abc123'  # Read from a file or environmental variable in a real app

# Access scopes for YouTube API
SCOPE = 'https://www.googleapis.com/auth/youtube.force-ssl'

# Indicate where the API server will redirect the user after the user completes
# the authorization flow. The redirect URI is required. The value must exactly
# match one of the authorized redirect URIs for the OAuth 2.0 client, which you
# configured in the API Console. If this value doesn't match an authorized URI,
# you will get a 'redirect_uri_mismatch' error.
REDIRECT_URI = 'http://example.com/oauth2callback'

@app.route('/')
def index():
  if 'credentials' not in flask.session:
    return flask.redirect(flask.url_for('oauth2callback'))

  credentials = json.loads(flask.session['credentials'])

  if credentials['expires_in'] <= 0:
    return flask.redirect(flask.url_for('oauth2callback'))
  else: 
    headers = {'Authorization': 'Bearer {}'.format(credentials['access_token'])}
    req_uri = 'https://www.googleapis.com/youtube/v3/channels/list'
    r = requests.get(req_uri, headers=headers)
    return r.text 

@app.route('/oauth2callback')
def oauth2callback():
  if 'code' not in flask.request.args:
    state = str(uuid.uuid4())
    flask.session['state'] = state
    # Generate a url that asks permissions for the Drive activity
    # and Google Calendar scope. Then, redirect user to the url.
    auth_uri = ('https://accounts.google.com/o/oauth2/v2/auth?response_type=code'
                '&client_id={}&redirect_uri={}&scope={}&state={}').format(CLIENT_ID, REDIRECT_URI,
                                                                          SCOPE, state)
    return flask.redirect(auth_uri)
  else:
    if 'state' not in flask.request.args or flask.request.args['state'] != flask.session['state']:
      return 'State mismatch. Possible CSRF attack.', 400

    auth_code = flask.request.args.get('code')
    data = {'code': auth_code,
            'client_id': CLIENT_ID,
            'client_secret': CLIENT_SECRET,
            'redirect_uri': REDIRECT_URI,
            'grant_type': 'authorization_code'}

    # Exchange authorization code for access and refresh tokens (if access_type is offline)
    r = requests.post('https://oauth2.googleapis.com/token', data=data)
    flask.session['credentials'] = r.text
    return flask.redirect(flask.url_for('index'))

if __name__ == '__main__':
  import uuid
  app.secret_key = str(uuid.uuid4())
  app.debug = False
  app.run()

Правила проверки URI перенаправления

Google применяет следующие правила проверки к URI перенаправления, чтобы помочь разработчикам обеспечить безопасность своих приложений. Ваши URI перенаправления должны соответствовать этим правилам. Определение домена, хоста, пути, запроса, схемы и информации о пользователе см. в разделе 3 RFC 3986 , упомянутом ниже.

Правила проверки
Схема

URI перенаправления должны использовать схему HTTPS, а не обычный HTTP. URI локального хоста (включая URI IP-адреса локального хоста) не подпадают под это правило.

Хозяин

В качестве хостов нельзя использовать необработанные IP-адреса. IP-адреса локальных хостов не подпадают под это правило.

Домен
  • Домены верхнего уровня (TLD) должны принадлежать к общедоступному списку суффиксов .
  • В качестве домена хоста нельзя использовать “googleusercontent.com” .
  • URI перенаправления не могут содержать домены сокращателей URL (например, goo.gl ), если приложение не является владельцем этого домена. Более того, если приложение, владеющее доменом сокращателя, решает перенаправить пользователя на этот домен, то URI перенаправления должен либо содержать “/google-callback/” в своем пути, либо заканчиваться на “/google-callback” .
  • Информация о пользователе

    URI перенаправления не могут содержать подкомпонент userinfo.

    Путь

    URI перенаправления не могут содержать обход пути (также называемый возвратом к каталогу), который представляется символами “/..” или “\..” или их URL-кодировкой.

    Запрос

    URI перенаправления не могут содержать открытые перенаправления .

    Фрагмент

    URI перенаправления не могут содержать компонент фрагмента.

    Персонажи URI перенаправления не могут содержать определенные символы, в том числе:
    • Символы-заменители ( '*' )
    • Непечатаемые символы ASCII
    • Недопустимые процентные кодировки (любая процентная кодировка, которая не соответствует формату кодирования URL, где знак процента за которым следуют две шестнадцатеричные цифры).
    • Нулевые символы (закодированный нулевой символ, например, %00 , %C0%80 )

    Поэтапная авторизация

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

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

    В этом случае при входе в систему приложению может не потребоваться доступ к каким-либо областям действия (scopes). Однако, если пользователь попытается оценить видео, добавить видео в плейлист или выполнить другое действие на YouTube, приложение может запросить доступ к области действия https://www.googleapis.com/auth/youtube.force-ssl . Аналогично, приложение может запросить доступ к области действия https://www.googleapis.com/auth/calendar если пользователь попытается добавить событие в календарь.

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

    К токену доступа, полученному в результате поэтапной авторизации, применяются следующие правила:

    • Токен можно использовать для доступа к ресурсам, соответствующим любой из областей действия, объединенных в новую, комбинированную авторизацию.
    • При использовании токена обновления для комбинированной авторизации для получения токена доступа, этот токен доступа представляет собой комбинированную авторизацию и может использоваться для любого из значений scope , включенных в ответ.
    • Объединенная авторизация включает все области действия, предоставленные пользователем проекту API, даже если запросы на предоставление были отправлены от разных клиентов. Например, если пользователь предоставил доступ к одной области действия с помощью настольного клиента приложения, а затем предоставил другой доступ к той же области действия через мобильный клиент, объединенная авторизация будет включать обе области действия.
    • Если вы отзываете токен, представляющий собой объединенную авторизацию, доступ ко всем областям действия этой авторизации для соответствующего пользователя отзывается одновременно.

    В примерах кода для разных языков, приведенных на шаге 1: Установка параметров авторизации , и в примере URL-адреса перенаправления HTTP/REST на шаге 2: Перенаправление на сервер Google OAuth 2.0, используется инкрементальная авторизация. В приведенных ниже примерах кода также показан код, который необходимо добавить для использования инкрементальной авторизации.

    PHP

    $client->setIncludeGrantedScopes(true);

    Python

    В Python установите аргумент ключевого слова include_granted_scopes в true , чтобы гарантировать, что запрос авторизации будет включать ранее предоставленные области действия. Вполне возможно, что include_granted_scopes будет не единственным аргументом ключевого слова, который вы установите, как показано в примере ниже.

    authorization_url, state = flow.authorization_url(
        # Enable offline access so that you can refresh an access token without
        # re-prompting the user for permission. Recommended for web server apps.
        access_type='offline',
        # Enable incremental authorization. Recommended as a best practice.
        include_granted_scopes='true')

    Руби

    auth_client.update!(
      :additional_parameters => {"include_granted_scopes" => "true"}
    )

    Node.js

    const authorizationUrl = oauth2Client.generateAuthUrl({
      // 'online' (default) or 'offline' (gets refresh_token)
      access_type: 'offline',
      /** Pass in the scopes array defined above.
        * Alternatively, if only one scope is needed, you can pass a scope URL as a string */
      scope: scopes,
      // Enable incremental authorization. Recommended as a best practice.
      include_granted_scopes: true
    });

    HTTP/REST

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

    GET https://accounts.google.com/o/oauth2/v2/auth?
      scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fyt-analytics.readonly&
      access_type=offline&
      state=security_token%3D138rk%3Btarget_url%3Dhttp...index&
      redirect_uri=http%3A%2F%2Flocalhost%2Foauth2callback&
      response_type=code&
      client_id=client_id&
      include_granted_scopes=true
    
          

    Refreshing an access token (offline access)

    Access tokens periodically expire and become invalid credentials for a related API request. You can refresh an access token without prompting the user for permission (including when the user is not present) if you requested offline access to the scopes associated with the token.

    • If you use a Google API Client Library, the client object refreshes the access token as needed as long as you configure that object for offline access.
    • If you are not using a client library, you need to set the access_type HTTP query parameter to offline when redirecting the user to Google's OAuth 2.0 server. In that case, Google's authorization server returns a refresh token when you exchange an authorization code for an access token. Then, if the access token expires (or at any other time), you can use a refresh token to obtain a new access token.

    Requesting offline access is a requirement for any application that needs to access a Google API when the user is not present. For example, an app that performs backup services or executes actions at predetermined times needs to be able to refresh its access token when the user is not present. The default style of access is called online.

    Server-side web applications, installed applications, and devices all obtain refresh tokens during the authorization process. Refresh tokens are not typically used in client-side (JavaScript) web applications.

    PHP

    If your application needs offline access to a Google API, set the API client's access type to offline:

    $client->setAccessType("offline");

    После того как пользователь предоставит автономный доступ к запрошенным областям действия, вы можете продолжать использовать API-клиент для доступа к API Google от имени пользователя, когда пользователь находится в автономном режиме. Объект клиента будет обновлять токен доступа по мере необходимости.

    Python

    В Python установите аргумент ключевого слова access_type в offline , чтобы гарантировать возможность обновления токена доступа без повторного запроса разрешения у пользователя. Вполне возможно, что access_type будет не единственным установленным аргументом ключевого слова, как показано в примере ниже.

    authorization_url, state = flow.authorization_url(
        # Enable offline access so that you can refresh an access token without
        # re-prompting the user for permission. Recommended for web server apps.
        access_type='offline',
        # Enable incremental authorization. Recommended as a best practice.
        include_granted_scopes='true')

    После того как пользователь предоставит автономный доступ к запрошенным областям действия, вы можете продолжать использовать API-клиент для доступа к API Google от имени пользователя, когда пользователь находится в автономном режиме. Объект клиента будет обновлять токен доступа по мере необходимости.

    Руби

    Если вашему приложению требуется доступ к API Google в автономном режиме, установите тип доступа клиента API на offline :

    auth_client.update!(
      :additional_parameters => {"access_type" => "offline"}
    )

    После того как пользователь предоставит автономный доступ к запрошенным областям действия, вы можете продолжать использовать API-клиент для доступа к API Google от имени пользователя, когда пользователь находится в автономном режиме. Объект клиента будет обновлять токен доступа по мере необходимости.

    Node.js

    Если вашему приложению требуется доступ к API Google в автономном режиме, установите тип доступа клиента API на offline :

    const authorizationUrl = oauth2Client.generateAuthUrl({
      // 'online' (default) or 'offline' (gets refresh_token)
      access_type: 'offline',
      /** Pass in the scopes array defined above.
        * Alternatively, if only one scope is needed, you can pass a scope URL as a string */
      scope: scopes,
      // Enable incremental authorization. Recommended as a best practice.
      include_granted_scopes: true
    });

    После того как пользователь предоставит автономный доступ к запрошенным областям действия, вы можете продолжать использовать API-клиент для доступа к API Google от имени пользователя, когда пользователь находится в автономном режиме. Объект клиента будет обновлять токен доступа по мере необходимости.

    Срок действия токенов доступа истекает. Эта библиотека автоматически использует токен обновления для получения нового токена доступа, если срок действия старого истекает. Простой способ гарантировать, что вы всегда будете хранить самые актуальные токены, — использовать событие `tokens`:

    oauth2Client.on('tokens', (tokens) => {
      if (tokens.refresh_token) {
        // store the refresh_token in your secure persistent database
        console.log(tokens.refresh_token);
      }
      console.log(tokens.access_token);
    });

    Событие получения токена происходит только при первой авторизации, и для получения токена обновления необходимо установить access_type в offline при вызове метода generateAuthUrl . Если вы уже предоставили приложению необходимые разрешения, не установив соответствующие ограничения для получения токена обновления, вам потребуется повторно авторизовать приложение для получения нового токена обновления.

    Чтобы установить refresh_token позже, можно использовать метод setCredentials :

    oauth2Client.setCredentials({
      refresh_token: `STORED_REFRESH_TOKEN`
    });

    После получения клиентом токена обновления, токены доступа будут автоматически получены и обновлены при следующем обращении к API.

    HTTP/REST

    Для обновления токена доступа ваше приложение отправляет HTTPS POST запрос на сервер авторизации Google ( https://oauth2.googleapis.com/token ), который включает следующие параметры:

    Поля
    client_id Идентификатор клиента, полученный из API Console.
    client_secret Необязательный

    Секрет клиента получен из API Console.

    grant_type В соответствии со спецификацией OAuth 2.0 , значение этого поля должно быть установлено на refresh_token .
    refresh_token Токен обновления, полученный в результате обмена кодами авторизации.

    Следующий фрагмент кода демонстрирует пример запроса:

    POST /token HTTP/1.1
    Host: oauth2.googleapis.com
    Content-Type: application/x-www-form-urlencoded
    
    client_id=your_client_id&
    refresh_token=refresh_token&
    grant_type=refresh_token

    Пока пользователь не отозвал предоставленный приложению доступ, сервер токенов возвращает объект JSON, содержащий новый токен доступа. В следующем фрагменте кода показан пример ответа:

    {
      "access_token": "1/fFAGRNJru1FTz70BzhT3Zg",
      "expires_in": 3920,
      "scope": "https://www.googleapis.com/auth/drive.metadata.readonly",
      "token_type": "Bearer"
    }

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

    аннулирование токена

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

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

    PHP

    Для программного отзыва токена вызовите функцию revokeToken() :

    $client->revokeToken();

    Python

    Для программного отзыва токена отправьте запрос на https://oauth2.googleapis.com/revoke , включив токен в качестве параметра и установив заголовок Content-Type :

    requests.post('https://oauth2.googleapis.com/revoke',
        params={'token': credentials.token},
        headers = {'content-type': 'application/x-www-form-urlencoded'})

    Руби

    Для программного отзыва токена отправьте HTTP-запрос к конечной точке oauth2.revoke :

    uri = URI('https://oauth2.googleapis.com/revoke')
    response = Net::HTTP.post_form(uri, 'token' => auth_client.access_token)

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

    Если запрос на отзыв успешно обработан, то код состояния ответа равен 200 В случае ошибки возвращается код состояния 400 вместе с кодом ошибки.

    Node.js

    Для программного отзыва токена отправьте HTTPS POST-запрос на конечную точку /revoke :

    const https = require('https');
    
    // Build the string for the POST request
    let postData = "token=" + userCredential.access_token;
    
    // Options for POST request to Google's OAuth 2.0 server to revoke a token
    let postOptions = {
      host: 'oauth2.googleapis.com',
      port: '443',
      path: '/revoke',
      method: 'POST',
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded',
        'Content-Length': Buffer.byteLength(postData)
      }
    };
    
    // Set up the request
    const postReq = https.request(postOptions, function (res) {
      res.setEncoding('utf8');
      res.on('data', d => {
        console.log('Response: ' + d);
      });
    });
    
    postReq.on('error', error => {
      console.log(error)
    });
    
    // Post the request with data
    postReq.write(postData);
    postReq.end();

    Параметр token может быть токеном доступа или токеном обновления. Если токен является токеном доступа и имеет соответствующий токен обновления, токен обновления также будет аннулирован.

    Если запрос на отзыв успешно обработан, то код состояния ответа равен 200 В случае ошибки возвращается код состояния 400 вместе с кодом ошибки.

    HTTP/REST

    Для программного отзыва токена ваше приложение отправляет запрос на https://oauth2.googleapis.com/revoke и передает токен в качестве параметра:

    curl -d -X -POST --header "Content-type:application/x-www-form-urlencoded" \
            https://oauth2.googleapis.com/revoke?token={token}

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

    Если запрос на отзыв успешно обработан, то HTTP-статус ответа равен 200 В случае ошибки возвращается HTTP-статус 400 вместе с кодом ошибки.

    Доступ по времени

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

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

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

    Дополнительным шагом для защиты учетных записей пользователей является внедрение защиты от изменений в учетных записях с помощью сервиса 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

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