适用于 TV 和受限输入设备应用的 OAuth 2.0

本文档介绍了如何实现 OAuth 2.0 授权,以便通过在电视、游戏机和打印机等设备上运行的应用访问 YouTube Data API。更具体地说,此流程专为无法访问浏览器或输入功能有限的设备而设计。

OAuth 2.0 可让用户与应用共享特定数据,同时保持其用户名、密码和其他信息的私密性。 例如,电视应用可以使用 OAuth 2.0 获取权限,以选择存储在 Google 云端硬盘中的文件。

由于使用此流程的应用会分发到各个设备,因此假设应用无法保密。它们可以在用户位于应用中时或应用在后台运行时访问 Google API。

替代方案

如果您要为 Android、iOS、macOS、Linux 或 Windows(包括通用 Windows 平台)等可访问浏览器且具有完整输入功能的平台编写应用,请使用适用于移动和桌面应用的 OAuth 2.0 流程。(即使您的应用是无图形界面的命令行工具,也应使用该流程。)

如果您想让用户使用其 Google 账号登录,并使用 JWT ID 令牌获取基本用户个人资料信息,请参阅在电视和输入受限的设备上登录

前提条件

为您的项目启用 API

任何调用 Google API 的应用都需要在 API Console中启用这些 API。

如需为您的项目启用该 API,请按以下步骤操作:

  1. Open the API Library 中的 Google API Console。
  2. If prompted, select a project, or create a new one.
  3. 使用“库”页面查找并启用 YouTube Data API。找到您的应用将使用的任何其他 API,并启用这些 API。

创建授权凭据

任何使用 OAuth 2.0 访问 Google API 的应用都必须具有授权凭据,以向 Google 的 OAuth 2.0 服务器表明应用的身份。以下步骤说明了如何为项目创建凭据。然后,您的应用可以使用这些凭据来访问您为相应项目启用的 API。

  1. Go to the Credentials page.
  2. 点击创建客户端
  3. 选择电视和受限输入设备应用类型。
  4. 为 OAuth 2.0 客户端命名,然后点击创建

确定访问权限范围

有了这一范围,您不但可以让应用仅请求访问所需的资源,而且还可以让用户控制其向您的应用授予的访问权限大小。因此,所请求的范围数量与获得用户同意的可能性之间可能存在反比关系。

在开始实现 OAuth 2.0 授权之前,我们建议您确定应用需要访问权限的范围。

<0x0

YouTube Data API v3 使用以下范围:

范围 说明
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 合作伙伴试演的隐私信息

查看已安装的应用或设备的允许的范围列表。

获取 OAuth 2.0 访问令牌

即使您的应用在输入功能有限的设备上运行,用户也必须单独访问输入功能更丰富的设备才能完成此授权流程。 该流程包含以下步骤:

  1. 您的应用会向 Google 的授权服务器发送请求,其中包含您的应用将请求访问的范围。
  2. 服务器会返回后续步骤中使用的多条信息,例如设备代码和用户代码。
  3. 您显示用户可在单独的设备上输入的信息,以授权您的应用。
  4. 您的应用开始轮询 Google 的授权服务器,以确定用户是否已授权您的应用。
  5. 用户切换到输入功能更丰富的设备,启动网络浏览器,前往第 3 步中显示的网址,然后输入第 3 步中也显示的代码。然后,用户可以授予(或拒绝)对应用的访问权限。
  6. 对轮询请求的下一次响应包含您的应用需要用来代表用户授权请求的令牌。(如果用户拒绝向您的应用授予访问权限,则响应不包含令牌。)

下图演示了此流程:

用户在具有浏览器的单独设备上登录

以下部分将详细介绍这些步骤。鉴于设备可能具有各种功能和运行时环境,本文档中显示的示例使用 curl 命令行实用程序。这些示例应易于移植到各种语言和运行时。

第 1 步:请求设备和用户代码

在此步骤中,您的设备会向 Google 的授权服务器 (https://oauth2.googleapis.com/device/code) 发送 HTTP POST 请求,其中包含您的应用以及您的应用想要以用户身份访问的访问范围。 您应使用 device_authorization_endpoint 元数据值从发现文档中检索此网址。包含以下 HTTP 请求参数:

参数
client_id 必需

应用的客户端 ID。您可以在 中找到此值。

scope 必需

一个以空格分隔的范围列表,用于标识应用可以代表用户访问的资源。这些值会告知 Google 向用户显示的同意屏幕。查看已安装的应用或设备的允许的范围列表。

有了这一范围,您不但可以让应用仅请求访问所需的资源,而且还可以让用户控制其向您的应用授予的访问权限大小。因此,所请求的授权范围数量与获得用户同意的可能性之间存在反比关系。

YouTube Data API v3 使用以下范围:

范围 说明
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 合作伙伴试演的隐私信息

OAuth 2.0 API 范围文档提供了您可能用于访问 Google API 的范围的完整列表。

示例

以下代码段显示了一个示例请求:

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

client_id=client_id&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fyoutube.force-ssl

此示例展示了用于发送相同请求的 curl 命令:

curl -d "client_id=client_id&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fyoutube.force-ssl" \
     https://oauth2.googleapis.com/device/code

第 2 步:处理授权服务器响应

授权服务器将返回以下响应之一:

成功响应

如果请求有效,您的响应将是一个包含以下属性的 JSON 对象:

属性
device_code Google 唯一分配的值,用于标识运行请求授权的应用的设备。用户将通过另一部输入功能更丰富的设备授权该设备。例如,用户可以使用笔记本电脑或手机授权在电视上运行的应用。在这种情况下,device_code 用于标识电视。

此代码可让运行应用的设备安全地确定用户是否已授予或拒绝访问权限。

expires_in device_codeuser_code 的有效时长(以秒为单位)。如果在此期间,用户未完成授权流程,并且您的设备也未轮询以检索有关用户决定的信息,您可能需要从第 1 步重新开始此流程。
interval 设备在轮询请求之间应等待的时长(以秒为单位)。例如,如果该值为 5,您的设备应每 5 秒向 Google 的授权服务器发送一次轮询请求。如需了解详情,请参阅第 3 步
user_code 一种区分大小写的值,用于向 Google 标识应用请求访问的范围。您的界面将指示用户在输入功能更丰富的单独设备上输入此值。然后,Google 会使用该值在提示用户授予对应用的访问权限时显示正确的权限范围集。
verification_url 用户必须在单独的设备上前往的网址,以便输入 user_code 并授予或拒绝您的应用访问权限。您的界面也会显示此值。

以下代码段显示了示例响应:

{
  "device_code": "4/4-GMMhmHCXhWEzkobqIHGG_EnNYYsAkukHspeYUk9E8",
  "user_code": "GQVQ-JKEC",
  "verification_url": "https://www.google.com/device",
  "expires_in": 1800,
  "interval": 5
}

“超出配额”响应

如果您的设备代码请求已超出与您的客户端 ID 关联的配额,您将收到 403 响应,其中包含以下错误:

{
  "error_code": "rate_limit_exceeded"
}

在这种情况下,请使用回退策略来降低请求速率。

第 3 步:显示用户代码

向用户显示在第 2 步中获得的 verification_urluser_code。这两个值都可以包含 US-ASCII 字符集中的任何可打印字符。您向用户显示的内容应指示用户在另一台设备上前往 verification_url 并输入 user_code

设计界面时,请谨记以下规则:

  • user_code
    • user_code 必须显示在可处理 15 个“W”大小字符的字段中。换句话说,如果您能正确显示代码 WWWWWWWWWWWWWWW,则说明您的界面有效,我们建议您在测试 user_code 在界面中的显示方式时使用该字符串值。
    • user_code 区分大小写,不应以任何方式进行修改,例如更改大小写或插入其他格式设置字符。
  • verification_url
    • 显示 verification_url 的空间必须足够宽,能够容纳长度为 40 个字符的网址字符串。
    • 您不得以任何方式修改 verification_url,除非选择性地移除用于显示的方案。如果您确实打算出于显示原因从网址中剥离方案(例如 https://),请确保您的应用可以处理 httphttps 变体。

第 4 步:轮询 Google 的授权服务器

由于用户将使用单独的设备前往 verification_url 并授予(或拒绝)访问权限,因此当用户响应访问请求时,请求设备不会自动收到通知。因此,请求设备需要轮询 Google 的授权服务器,以确定用户何时响应了请求。

请求设备应继续发送轮询请求,直到收到表明用户已响应访问权限请求的响应,或者直到在 第 2 步中获得的 device_codeuser_code 过期。第 2 步中返回的 interval 指定了请求之间等待的时间(以秒为单位)。

要轮询的端点的网址为 https://oauth2.googleapis.com/token。轮询请求包含以下参数:

参数
client_id 应用的客户端 ID。您可以在 中找到此值。
client_secret 所提供 client_id 的客户端密钥。您可以在 中找到此值。
device_code 授权服务器在第 2 步中返回的 device_code
grant_type 并将此值设为 urn:ietf:params:oauth:grant-type:device_code

示例

以下代码段显示了一个示例请求:

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

client_id=client_id&
client_secret=client_secret&
device_code=device_code&
grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Adevice_code

此示例展示了用于发送相同请求的 curl 命令:

curl -d "client_id=client_id&client_secret=client_secret& \
         device_code=device_code& \
         grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Adevice_code" \
         -H "Content-Type: application/x-www-form-urlencoded" \
         https://oauth2.googleapis.com/token

第 5 步:用户响应访问权限请求

下图显示了一个与用户在导航到您在第 3 步中显示的 verification_url 时看到的页面类似的页面:

通过输入代码连接设备

输入 user_code 并登录 Google(如果尚未登录)后,用户会看到一个同意屏幕,如下所示:

设备客户端的同意屏幕示例

第 6 步:处理对轮询请求的响应

Google 的授权服务器会以以下某一种响应来响应每个轮询请求:

已授予访问权限

如果用户授予了设备访问权限(通过点击同意屏幕上的 Allow),则响应中会包含访问令牌和刷新令牌。借助这些令牌,您的设备可以代表用户访问 Google API。(响应中的 scope 属性决定了设备可以访问哪些 API。)

在这种情况下,API 响应包含以下字段:

字段
access_token 您的应用发送的用于授权 Google API 请求的令牌。
expires_in 访问令牌的剩余生命周期(以秒为单位)。
refresh_token 可用于获取新访问令牌的令牌。刷新令牌在用户撤消访问权限或刷新令牌过期之前一直有效。 请注意,系统始终会为设备返回刷新令牌。
refresh_token_expires_in 刷新令牌的剩余有效期(以秒为单位)。仅当用户授予基于时间的访问权限时,才会设置此值。
scope access_token 授予的访问权限范围,表示为以空格分隔且区分大小写的字符串列表。
token_type 返回的令牌的类型。目前,此字段的值始终设置为 Bearer

以下代码段显示了示例响应:

{
  "access_token": "1/fFAGRNJru1FTz70BzhT3Zg",
  "expires_in": 3920,
  "scope": "openid https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email",
  "token_type": "Bearer",
  "refresh_token": "1/xEoDL4iW3cxlI7yDbSRFYNG01kVKM2C-259HOF2aQbI"
}

访问令牌的生命周期有限。如果您的应用需要长时间访问某个 API,则可以使用刷新令牌来获取新的访问令牌。如果您的应用需要此类访问权限,则应存储刷新令牌以供日后使用。

访问遭拒

如果用户拒绝授予设备访问权限,则服务器响应具有 403 HTTP 响应状态代码 (Forbidden)。该响应包含以下错误:

{
  "error": "access_denied",
  "error_description": "Forbidden"
}

授权待处理

如果用户尚未完成授权流程,服务器会返回 428 HTTP 响应状态代码 (Precondition Required)。响应包含以下错误:

{
  "error": "authorization_pending",
  "error_description": "Precondition Required"
}

轮询过于频繁

如果设备发送轮询请求的频率过高,服务器会返回 403 HTTP 响应状态代码 (Forbidden)。该响应包含以下错误:

{
  "error": "slow_down",
  "error_description": "Forbidden"
}

其他错误

如果轮询请求缺少任何必需参数或包含错误的参数值,授权服务器也会返回错误。这些请求通常具有 400 (Bad Request) 或 401 (Unauthorized) HTTP 响应状态代码。这些错误包括:

错误 HTTP 状态代码 说明
admin_policy_enforced 400 由于 Google Workspace 管理员的政策,相应 Google 账号无法授权一个或多个请求的范围。如需详细了解管理员如何限制对范围的访问权限,直到明确授予您的 OAuth 客户端 ID 访问权限为止,请参阅 Google Workspace 管理员帮助文章控制哪些第三方应用和内部应用可以访问 Google Workspace 数据
invalid_client 401

未找到 OAuth 客户端。例如,如果 client_id 参数值无效,则会发生此错误。

OAuth 客户端类型不正确。确保将相应客户端 ID 的应用类型设置为电视和受限输入设备

invalid_grant 400 code 参数值无效、已被声明或无法解析。
unsupported_grant_type 400 grant_type 参数值无效。
org_internal 403 请求中的 OAuth 客户端 ID 属于一个项目,该项目限制对特定 Google Cloud 组织中的 Google 账号的访问权限。确认 OAuth 应用的用户类型配置

调用 Google API

应用获得访问令牌后,如果 API 所需的访问范围已获授权,您就可以使用该令牌代表指定的用户账号调用 Google API。为此,请在向 API 发出的请求中添加访问令牌,方法是添加 access_token 查询参数或 Authorization HTTP 标头 Bearer 值。如果可以,最好使用 HTTP 标头,因为查询字符串往往会显示在服务器日志中。在大多数情况下,您可以使用客户端库来设置对 Google API 的调用(例如,调用 YouTube Live Streaming API 时)。

请注意,YouTube Live Streaming API 不支持服务账号流程。由于无法将服务账号与 YouTube 账号相关联,因此尝试使用此流程授权请求会生成 NoLinkedYouTubeAccount 错误。

您可以在 OAuth 2.0 Playground 中试用所有 Google API 并查看其范围。

HTTP GET 示例

使用 Authorization: Bearer HTTP 标头对 liveBroadcasts.list 端点(YouTube Live Streaming API)的调用可能如下所示。请注意,您需要指定自己的访问令牌:

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

以下是使用 access_token 查询字符串参数针对已通过身份验证的用户对同一 API 的调用:

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

刷新访问令牌

访问令牌会定期过期,并成为相关 API 请求的无效凭据。如果您请求离线访问与令牌关联的范围,则可以刷新访问令牌,而不提示用户授予权限(包括用户不在场时)。

如需刷新访问令牌,您的应用会向 Google 的授权服务器 (https://oauth2.googleapis.com/token) 发送 HTTPS POST 请求,其中包含以下参数:

字段
client_id API Console获取的客户端 ID。
client_secret API Console获取的客户端密钥。
grant_type OAuth 2.0 规范中所定义,此字段的值必须设置为 refresh_token
refresh_token 从授权代码交换中返回的刷新令牌。

以下代码段显示了一个示例请求:

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

client_id=your_client_id&
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 请求,以确保移除之前授予应用的权限。

如需以编程方式撤消令牌,您的应用可以向 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 以及错误代码。

允许的范围

设备 OAuth 2.0 流程仅支持以下范围:

OpenID ConnectGoogle 登录

  • email
  • openid
  • profile

Drive API

  • https://www.googleapis.com/auth/drive.appdata
  • https://www.googleapis.com/auth/drive.file

YouTube API

  • https://www.googleapis.com/auth/youtube
  • https://www.googleapis.com/auth/youtube.readonly

基于时间的访问权限

基于时间的访问权限允许用户在有限的时间内授予您的应用对其数据的访问权限,以完成某项操作。在意见征求流程中,部分 Google 产品会提供基于时间的访问权限,让用户可以选择在有限的时间内授予访问权限。例如, Data Portability API 可实现一次性数据转移。

当用户向您的应用授予基于时间的访问权限时,刷新令牌将在指定时长后过期。请注意,在特定情况下,刷新令牌可能会提前失效;如需了解详情,请参阅这些情况。在授权码交换响应中返回的 refresh_token_expires_in 字段表示在这种情况下刷新令牌的剩余有效时间。

实现跨账号保护

为保护用户账号,您还应采取一项措施,即利用 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

如需详细了解如何实现跨账号保护,以及查看可用事件的完整列表,请参阅 使用跨账号保护功能保护用户账号 页面。