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

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

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

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

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

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

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

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

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

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

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

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

Любое приложение, которое вызывает API Google, должно включить эти API в .

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

  1. в .
  2. Используйте страницу библиотеки, чтобы найти и включить API данных YouTube. Найдите любые другие API, которые будет использовать ваше приложение, и включите их.

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

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

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

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

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

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

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

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

Прежде чем приступить к реализации авторизации 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 .
  • Клиентская библиотека API Google для PHP:

    composer require google/apiclient:^2.15.0

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

Питон

Чтобы запустить примеры кода Python из этого документа, вам потребуется:

  • Python 3.7 или выше
  • Инструмент управления пакетами pip .
  • Клиентская библиотека API Google для версии 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, приведенные в этом документе, вам потребуется:

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

    gem install googleauth
  • Клиентские библиотеки для Google API Диска и Календаря:

    gem install google-apis-drive_v3 google-apis-calendar_v3
  • Платформа веб-приложений Sinatra Ruby.

    gem install sinatra

Node.js

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

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

    npm install googleapis crypto express express-session

HTTP/REST

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

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

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

В приведенном ниже списке кратко суммированы эти шаги:

  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);

Питон

В следующем фрагменте кода используется модуль 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',
            'https://www.googleapis.com/auth/calendar.readonly'])

# 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'
require 'google/apis/calendar_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 
# Access scopes for two non-Sign-In scopes: Read-only Drive activity and Google Calendar.
scope = ['Google::Apis::DriveV3::AUTH_DRIVE_METADATA_READONLY',
         'Google::Apis::CalendarV3::AUTH_CALENDAR_READONLY']

# 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 two non-Sign-In scopes: Read-only Drive activity and Google Calendar.
const scopes = [
  'https://www.googleapis.com/auth/youtube.force-ssl',
  'https://www.googleapis.com/auth/calendar.readonly'
];

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

Конечная точка Google OAuth 2.0 находится по адресу https://accounts.google.com/o/oauth2/v2/auth . Эта конечная точка доступна только через HTTPS. Обычные HTTP-соединения отклоняются.

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

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

Идентификатор клиента для вашего приложения. Вы можете найти это значение в .

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

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

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

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

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

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

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

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

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

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 после того, как пользователь соглашается или отклоняет запрос доступа вашего приложения.

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

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

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

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

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

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

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

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

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

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

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

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

PHP

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

Питон

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

return flask.redirect(authorization_url)

Руби

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

Node.js

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

HTTP/REST

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

Ниже показан пример URL-адреса с разрывами строк и пробелами для удобства чтения. URL-адрес запрашивает доступ к области, которая разрешает доступ для получения данных YouTube пользователя. Он использует добавочную авторизацию ( include_granted_scopes=true ), чтобы гарантировать, что новый токен доступа охватывает все области, к которым пользователь ранее предоставил доступ приложению. В примере также задано несколько других параметров.

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

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

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

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

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

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

Ошибки

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

admin_policy_enforced

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

disallowed_useragent

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

Андроид

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

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

iOS

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

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

org_internal

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

invalid_client

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

invalid_grant

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

redirect_uri_mismatch

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

Параметр redirect_uri может относиться к внеполосному потоку OAuth (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

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

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

После завершения потока OAuth 2.0 вы должны быть перенаправлены на http://localhost/oauth2callback , что, скорее всего, приведет к ошибке 404 NOT FOUND , если ваш локальный компьютер не обслуживает файл по этому адресу. Следующий шаг предоставляет более подробную информацию об информации, возвращаемой в URI, когда пользователь перенаправляется обратно в ваше приложение.

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

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

PHP

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

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

Питон

На странице обратного вызова используйте библиотеку 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 the session.
# ACTION ITEM for developers:
#     Store user's access and refresh tokens in your data store if
#     incorporating this code into your real app.
credentials = flow.credentials
flask.session['credentials'] = {
    'token': credentials.token,
    'refresh_token': credentials.refresh_token,
    'token_uri': credentials.token_uri,
    'client_id': credentials.client_id,
    'client_secret': credentials.client_secret,
    '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 Идентификатор клиента, полученный из .
client_secret Секрет клиента, полученный от .
code Код авторизации, возвращенный из первоначального запроса.
grant_type Как определено в спецификации OAuth 2.0 , значение этого поля должно быть установлено в authorization_code .
redirect_uri Один из URI перенаправления, перечисленных для вашего проекта в для данного 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&
client_secret=your_client_secret&
redirect_uri=https%3A//oauth2.example.com/code&
grant_type=authorization_code

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

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

Поля
access_token Токен, который ваше приложение отправляет для авторизации запроса Google API.
expires_in Оставшийся срок действия токена доступа в секундах.
refresh_token Токен, который можно использовать для получения нового токена доступа. Токены обновления действительны до тех пор, пока пользователь не отзовет доступ. Опять же, это поле присутствует в этом ответе только в том случае, если вы установили для параметра access_type значение offline в первоначальном запросе к серверу авторизации Google.
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 https://www.googleapis.com/auth/calendar.readonly",
  "refresh_token": "1//xEoDL4iW3cxlI7yDbSRFYNG01kVKM2C-259HOF2aQbI"
}

Ошибки

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

invalid_grant

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

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

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

PHP

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

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

// Determine which scopes user granted and build a dictionary
$granted_scopes_dict = [
  'Drive' => str_contains($granted_scopes, Google\Service\Drive::DRIVE_METADATA_READONLY),
  'Calendar' => str_contains($granted_scopes, Google\Service\Calendar::CALENDAR_READONLY)
];

Питон

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

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

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

def check_granted_scopes(credentials):
  features = {}
  if 'https://www.googleapis.com/auth/drive.metadata.readonly' in credentials['granted_scopes']:
    features['drive'] = True
  else:
    features['drive'] = False

  if 'https://www.googleapis.com/auth/calendar.readonly' in credentials['granted_scopes']:
    features['calendar'] = True
  else:
    features['calendar'] = False

  return features

Руби

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

# User authorized the request. Now, check which scopes were granted.
if credentials.scope.include?(Google::Apis::DriveV3::AUTH_DRIVE_METADATA_READONLY)
  # User authorized read-only Drive activity permission.
  # Calling the APIs, etc
else
  # User didn't authorize read-only Drive activity permission.
  # Update UX and application accordingly
end

# Check if user authorized Calendar read permission.
if credentials.scope.include?(Google::Apis::CalendarV3::AUTH_CALENDAR_READONLY)
  # User authorized Calendar read permission.
  # Calling the APIs, etc.
else
  # User didn't authorize Calendar read 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 read-only Drive activity permission.
  // Calling the APIs, etc.
}
else
{
  // User didn't authorize read-only Drive activity permission.
  // Update UX and application accordingly
}

// Check if user authorized Calendar read permission.
if (tokens.scope.includes('https://www.googleapis.com/auth/calendar.readonly'))
{
  // User authorized Calendar read permission.
  // Calling the APIs, etc.
}
else
{
  // User didn't authorize Calendar read permission.
  // Update UX and application accordingly
}

HTTP/REST

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

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

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

Вызов API Google

PHP

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

  1. Если вам нужно применить токен доступа к новому объекту Google\Client — например, если вы сохранили токен доступа в сеансе пользователя — используйте метод setAccessToken :
    $client->setAccessToken($access_token);
  2. Создайте объект службы для API, который вы хотите вызвать. Вы создаете объект службы, предоставляя авторизованный объект Google\Client конструктору API, который вы хотите вызвать. Например, чтобы вызвать API данных YouTube:
    $youtube = new Google_Service_YouTube($client);
  3. Отправляйте запросы к службе API, используя интерфейс, предоставляемый объектом службы . Например, чтобы использовать API данных YouTube для получения списка прямых трансляций для канала проверенного пользователя:
    $broadcasts = $youtube->liveBroadcasts->listLiveBroadcasts('id,snippet', [ 'mine' => true ]);

Питон

После получения токена доступа ваше приложение может использовать этот токен для авторизации запросов 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, используя интерфейс, предоставляемый объектом службы . Например, чтобы использовать API данных YouTube для получения списка прямых трансляций для канала проверенного пользователя:
    broadcasts = youtube.liveBroadcasts().list(part='id,snippet', mine=True).execute()

Руби

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

  1. Создайте объект службы для API, который вы хотите вызвать. Например, чтобы вызвать версию 3 API данных YouTube:
    youtube = Google::Apis::YoutubeV3::YouTubeService.new
  2. Установите учетные данные в сервисе:
    youtube.authorization = credentials
  3. Отправляйте запросы к службе API, используя интерфейс, предоставляемый объектом службы . Например, чтобы использовать API данных YouTube для получения списка прямых трансляций для канала проверенного пользователя:
    broadcasts = youtube.list_liveBroadcasts('id,snippet', mine: true)

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

broadcasts = youtube.list_liveBroadcasts('id,snippet', mine: true)

Node.js

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

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

// Example of using Google Drive API to list filenames in user's Drive.
const drive = google.drive('v3');
drive.files.list({
  auth: oauth2Client,
  pageSize: 10,
  fields: 'nextPageToken, files(id, name)',
}, (err1, res1) => {
  if (err1) return console.log('The API returned an error: ' + err1);
  const files = res1.data.files;
  if (files.length) {
    console.log('Files:');
    files.map((file) => {
      console.log(`${file.name} (${file.id})`);
    });
  } else {
    console.log('No files found.');
  }
});

HTTP/REST

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

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

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

Примеры HTTP GET

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

GET /youtube/v3/liveBroadcasts?part=id%2Csnippet&mine=true HTTP/1.1
Host: www.googleapis.com
Authorization: Bearer access_token

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

GET https://www.googleapis.com/youtube/v3/liveBroadcasts?access_token=access_token&part=id%2Csnippet&mine=true

примеры curl

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

curl -H "Authorization: Bearer access_token" https://www.googleapis.com/youtube/v3/liveBroadcasts?part=id%2Csnippet&mine=true

Или, альтернативно, опция параметра строки запроса:

curl https://www.googleapis.com/youtube/v3/liveBroadcasts?access_token=access_token&part=id%2Csnippet&mine=true

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

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

PHP

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

  1. В , добавьте 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']);
  
  // Check if user granted Drive permission
  if ($_SESSION['granted_scopes_dict']['Drive']) {
    echo "Drive feature is enabled.";
    echo "</br>";
    $drive = new Drive($client);
    $files = array();
    $response = $drive->files->listFiles(array());
    foreach ($response->files as $file) {
        echo "File: " . $file->name . " (" . $file->id . ")";
        echo "</br>";
    }
  } else {
    echo "Drive feature is NOT enabled.";
    echo "</br>";
  }

   // Check if user granted Calendar permission
  if ($_SESSION['granted_scopes_dict']['Calendar']) {
    echo "Calendar feature is enabled.";
    echo "</br>";
  } else {
    echo "Calendar feature is NOT enabled.";
    echo "</br>";
  }
}
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();
  
  // Space-separated string of granted scopes if it exists, otherwise null.
  $granted_scopes = $client->getOAuth2Service()->getGrantedScope();

  // Determine which scopes user granted and build a dictionary
  $granted_scopes_dict = [
    'Drive' => str_contains($granted_scopes, Google\Service\Drive::DRIVE_METADATA_READONLY),
    'Calendar' => str_contains($granted_scopes, Google\Service\Calendar::CALENDAR_READONLY)
  ];
  $_SESSION['granted_scopes_dict'] = $granted_scopes_dict;
  
  $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'];
}
?>

Питон

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

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

import os
import flask
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',
          'https://www.googleapis.com/auth/calendar.readonly']
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('/drive')
def drive_api_request():
  if 'credentials' not in flask.session:
    return flask.redirect('authorize')

  features = flask.session['features']

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

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

    broadcasts = youtube.liveBroadcasts().list(part='id,snippet', mine=True).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(**broadcasts)
  else:
    # User didn't authorize read-only Drive activity permission.
    # Update UX and application accordingly
    return '<p>Drive feature is not enabled.</p>'

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

      features = flask.session['features']

      if features['calendar']:
        # User authorized Calendar read permission.
        # Calling the APIs, etc.
        return ('<p>User granted the Google Calendar read permission. '+
                'This sample code does not include code to call Calendar</p>')
      else:
        # User didn't authorize Calendar read permission.
        # Update UX and application accordingly
        return '<p>Calendar feature is not enabled.</p>'

@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
  
  credentials = credentials_to_dict(credentials)
  flask.session['credentials'] = credentials

  # Check which scopes user granted
  features = check_granted_scopes(credentials)
  flask.session['features'] = features
  return flask.redirect('/')
  

@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.')

  credentials = google.oauth2.credentials.Credentials(
    **flask.session['credentials'])

  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:
    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,
          'token_uri': credentials.token_uri,
          'client_id': credentials.client_id,
          'client_secret': credentials.client_secret,
          'granted_scopes': credentials.granted_scopes}

def check_granted_scopes(credentials):
  features = {}
  if 'https://www.googleapis.com/auth/youtube.force-ssl' in credentials['granted_scopes']:
    features['drive'] = True
  else:
    features['drive'] = False

  if 'https://www.googleapis.com/auth/calendar.readonly' in credentials['granted_scopes']:
    features['calendar'] = True
  else:
    features['calendar'] = False

  return features

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="/authorize">Test the auth flow directly</a></td>' +
          '<td>Go directly to the authorization flow. If there are stored ' +
          '    credentials, you still might not be prompted to reauthorize ' +
          '    the application.</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 .
  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 'google/apis/calendar_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 two non-Sign-In scopes: Read-only Drive activity and Google Calendar.
  scope = ['Google::Apis::DriveV3::AUTH_DRIVE_METADATA_READONLY',
           'Google::Apis::CalendarV3::AUTH_CALENDAR_READONLY']

  # 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 the request. Now, check which scopes were granted.
  if credentials.scope.include?(Google::Apis::DriveV3::AUTH_DRIVE_METADATA_READONLY)
    # User authorized read-only Drive activity permission.
    # Example of using Google Drive API to list filenames in user's Drive.
    youtube = Google::Apis::YoutubeV3::YouTubeService.new
    broadcasts = youtube.list_liveBroadcasts('id,snippet', mine: true)
    
    "<pre>#{JSON.pretty_generate(broadcasts.to_h)}</pre>"
  else
    # User didn't authorize read-only Drive activity permission.
    # Update UX and application accordingly
  end

  # Check if user authorized Calendar read permission.
  if credentials.scope.include?(Google::Apis::CalendarV3::AUTH_CALENDAR_READONLY)
    # User authorized Calendar read permission.
    # Calling the APIs, etc.
  else
    # User didn't authorize Calendar read permission.
    # Update UX and application accordingly
  end
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. В , добавьте URL-адрес локального компьютера в список URL-адресов перенаправления. Например, добавьте http://localhost .
  2. Убедитесь, что у вас установлена ​​служебная LTS, активная LTS или текущая версия Node.js.
  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 two non-Sign-In scopes: Read-only Drive activity and Google Calendar.
const scopes = [
  'https://www.googleapis.com/auth/youtube.force-ssl',
  'https://www.googleapis.com/auth/calendar.readonly'
];

/* 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;
      
      // User authorized the request. Now, check which scopes were granted.
      if (tokens.scope.includes('https://www.googleapis.com/auth/youtube.force-ssl'))
      {
        // User authorized read-only Drive activity permission.
        // Example of using Google Drive API to list filenames in user's Drive.
        const drive = google.drive('v3');
        drive.files.list({
          auth: oauth2Client,
          pageSize: 10,
          fields: 'nextPageToken, files(id, name)',
        }, (err1, res1) => {
          if (err1) return console.log('The API returned an error: ' + err1);
          const files = res1.data.files;
          if (files.length) {
            console.log('Files:');
            files.map((file) => {
              console.log(`${file.name} (${file.id})`);
            });
          } else {
            console.log('No files found.');
          }
        });
      }
      else
      {
        // User didn't authorize read-only Drive activity permission.
        // Update UX and application accordingly
      }

      // Check if user authorized Calendar read permission.
      if (tokens.scope.includes('https://www.googleapis.com/auth/calendar.readonly'))
      {
        // User authorized Calendar read permission.
        // Calling the APIs, etc.
      }
      else
      {
        // User didn't authorize Calendar read permission.
        // Update UX and application accordingly
      }
    }
  });

  // 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 two non-Sign-In scopes: Read-only Drive activity and Google Calendar.
SCOPE = 'https://www.googleapis.com/auth/youtube.force-ssl https://www.googleapis.com/auth/calendar.readonly'

# 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: 
    # User authorized the request. Now, check which scopes were granted.
    if 'https://www.googleapis.com/auth/drive.metadata.readonly' in credentials['scope']:
      # User authorized read-only Drive activity permission.
      # Example of using Google Drive API to list filenames in user's Drive.
      headers = {'Authorization': 'Bearer {}'.format(credentials['access_token'])}
      req_uri = 'https://youtube.googleapis.com/youtube/v3/liveBroadcasts'
      r = requests.get(req_uri, headers=headers).text
    else:
      # User didn't authorize read-only Drive activity permission.
      # Update UX and application accordingly
      r = 'User did not authorize Drive permission.'

    # Check if user authorized Calendar read permission.
    if 'https://www.googleapis.com/auth/calendar.readonly' in credentials['scope']:
      # User authorized Calendar read permission.
      # Calling the APIs, etc.
      r += 'User authorized Calendar permission.'
    else:
      # User didn't authorize Calendar read permission.
      # Update UX and application accordingly
      r += 'User did not authorize Calendar permission.'

  return r

@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-кодирования, состоящей из знака процента, за которым следуют две шестнадцатеричные цифры).
    • Нулевые символы (закодированный NULL-символ, например, %00 , %C0%80 )

    Инкрементная авторизация

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

    Например, предположим, что приложение получает данные для канала YouTube прошедшего проверку подлинности пользователя, а также позволяет пользователю получать данные YouTube Analytics с помощью специального потока. В этом случае во время входа приложение может запросить доступ только к области https://www.googleapis.com/auth/youtube.force-ssl . Однако если пользователь попытается получить доступ к данным Analytics для своего канала, приложение также может запросить доступ к области https://www.googleapis.com/auth/yt-analytics.readonly .

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

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

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

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

    PHP

    $client->setIncludeGrantedScopes(true);

    Питон

    В 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 пользователя в дополнение к любому другому доступу, который пользователь уже предоставил приложению.

    GET https://accounts.google.com/o/oauth2/v2/auth?
      scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fyoutube.force-ssl&
      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 установите аргумент ключевого слова 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 Идентификатор клиента, полученный из .
    client_secret Секрет клиента, полученный от .
    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&
    client_secret=your_client_secret&
    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 https://www.googleapis.com/auth/calendar.readonly",
      "token_type": "Bearer"
    }

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

    Отзыв токена

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

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

    PHP

    Чтобы программно отозвать токен, вызовите revokeToken() :

    $client->revokeToken();

    Питон

    Чтобы программно отозвать токен, отправьте запрос 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();

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

    Если отзыв успешно обработан, код состояния ответа — 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. Эта служба позволяет вам подписаться на уведомления о событиях безопасности, которые предоставляют вашему приложению информацию о серьезных изменениях в учетной записи пользователя. Затем вы можете использовать эту информацию, чтобы принять меры в зависимости от того, как вы решите реагировать на события.

    Вот некоторые примеры типов событий, отправляемых в ваше приложение службой защиты нескольких аккаунтов 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

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