本文档介绍了如何实现 OAuth 2.0 授权,以通过在电视、游戏机和打印机等设备上运行的应用访问 YouTube Data API。更具体地说,此流程适用于无法访问浏览器或输入功能有限的设备。
OAuth 2.0 允许用户与应用共享特定数据,同时保持其用户名、密码和其他信息的私密性。例如,TV 应用可以使用 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,请按以下步骤操作:
- Open the API Library (在 Google API Console中)。
- If prompted, select a project, or create a new one.
- 使用媒体库页面找到并启用 YouTube Data API。查找您的应用将使用的任何其他 API,并启用这些 API。
创建授权凭据
任何使用 OAuth 2.0 访问 Google API 的应用都必须具有授权凭据,用于向 Google 的 OAuth 2.0 服务器标识应用。以下步骤说明了如何为项目创建凭据。然后,您的应用可以使用这些凭据访问您已为该项目启用的 API。
- Go to the Credentials page.
- 依次点击创建凭据 > OAuth 客户端 ID。
- 选择电视和受限输入设备应用类型。
- 为您的 OAuth 2.0 客户端命名,然后点击创建。
确定访问权限范围
借助范围,您的应用可以仅请求访问所需的资源,同时用户还可以控制他们向您的应用授予的访问权限大小。因此,请求的范围数量与征得用户同意的可能性之间可能存在反向关系。
在开始实现 OAuth 2.0 授权之前,我们建议您确定应用需要访问权限的范围。
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 访问令牌
即使您的应用在输入功能有限的设备上运行,用户也必须对输入功能更丰富的设备拥有单独的访问权限才能完成此授权流程。该流程包含以下步骤:
- 您的应用向 Google 的授权服务器发送请求,用于标识您的应用将请求访问权限的范围。
- 服务器会返回后续步骤中使用的多条信息,例如设备代码和用户代码。
- 您显示用户可在单独的设备上输入的信息,以向您的应用授权。
- 您的应用开始轮询 Google 的授权服务器,以确定用户是否已向您的应用授权。
- 用户切换到具有更丰富输入功能的设备,启动网络浏览器,转到第 3 步中显示的网址,并输入第 3 步中显示的代码。然后,用户可以授予(或拒绝)对您的应用的访问权限。
- 对轮询请求的下一个响应包含您的应用代表用户为请求授权时所需的令牌。(如果用户拒绝访问您的应用,则响应不包含令牌。)
下图演示了此过程:
![用户在装有浏览器的独立设备上登录](https://developers.google.cn/static/identity/protocols/images/oauth2/device/flow.png?authuser=4&hl=sr)
以下部分将详细介绍这些步骤。考虑到设备可能具有的功能范围和运行时环境,本文档中显示的示例使用的是 curl
命令行实用程序。这些示例应该可以轻松移植到各种语言和运行时。
第 1 步:请求设备和用户代码
在此步骤中,您的设备会向 Google 的授权服务器 (https://oauth2.googleapis.com/device/code
) 发送一个 HTTP POST 请求,该请求用于标识您的应用以及您的应用要以用户身份访问的访问权限范围。您应使用 device_authorization_endpoint
元数据值从发现文档中检索此网址。添加以下 HTTP 请求参数:
参数 | |||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
client_id |
必需
应用的客户端 ID。您可以在 API Console Credentials page中找到此值。 |
||||||||||||||||
scope |
必需
以空格分隔的范围列表,用于标识应用可以代表用户访问的资源。这些值会告知 Google 向用户显示的同意屏幕。请参阅允许的范围列表,查看已安装的应用或设备。 借助范围,您的应用可以仅请求访问所需的资源,同时用户还可以控制他们向您的应用授予的访问权限大小。因此,请求的范围数量与征得用户同意的可能性之间是相反的。 YouTube Data API v3 使用以下范围:
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.readonly
以下示例展示了用于发送同一请求的 curl
命令:
curl -d "client_id=client_id&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fyoutube.readonly" \ https://oauth2.googleapis.com/device/code
第 2 步:处理授权服务器响应
授权服务器将返回以下响应之一:
成功响应
如果请求有效,响应将是包含以下属性的 JSON 对象:
属性 | |
---|---|
device_code |
Google 唯一分配的值,用于标识运行请求授权的应用的设备。用户将通过另一个具有更丰富输入功能的设备向该设备授权。例如,用户可以使用笔记本电脑或手机为 TV 上运行的应用授权。在这种情况下,device_code 用于标识电视。
此代码可让运行应用的设备安全地确定用户是授予还是拒绝了访问权限。 |
expires_in |
device_code 和 user_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_url
和 user_code
。这两个值可以包含 US-ASCII 字符集中的任何可打印字符。您向用户显示的内容应指示用户在另一部设备上导航到 verification_url
并输入 user_code
。
设计界面 (UI) 时,请牢记以下规则:
user_code
user_code
必须显示在可处理 15 个“W”大小字符的字段中。换言之,如果您可以正确显示代码WWWWWWWWWWWWWWW
,则界面有效,我们建议在测试user_code
在界面中的显示方式时使用该字符串值。user_code
区分大小写,不应以任何方式修改,例如更改大小写或插入其他格式字符。
verification_url
- 显示
verification_url
的空间必须足够宽,可以处理长度为 40 个字符的网址字符串。 - 除非可以视需要移除用于显示的方案,否则不应以任何方式修改
verification_url
。如果您出于显示原因打算从网址中去除架构(例如https://
),请确保您的应用可同时处理http
和https
变体。
- 显示
第 4 步:轮询 Google 的授权服务器
由于用户将使用单独的设备导航到 verification_url
并授予(或拒绝)访问权限,因此当用户响应访问请求时,请求设备不会自动收到通知。因此,发出请求的设备需要轮询 Google 的授权服务器,以确定用户何时响应了请求。
发出请求的设备应继续发送轮询请求,直到收到表明用户已响应访问请求的响应,或直到在
第 2 步中获取的 device_code
和 user_code
过期为止。第 2 步中返回的 interval
指定了请求之间等待的时间(以秒为单位)。
要轮询的端点的网址为 https://oauth2.googleapis.com/token
。轮询请求包含以下参数:
参数 | |
---|---|
client_id |
应用的客户端 ID。您可以在 API Console Credentials page中找到此值。 |
client_secret |
提供的 client_id 的客户端密钥。您可以在 API Console
Credentials page中找到此值。 |
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
时看到的页面:
![输入代码以连接设备](https://developers.google.cn/static/identity/protocols/images/oauth2/device/user-code.png?authuser=4&hl=sr)
输入 user_code
并登录 Google(如果尚未登录)后,用户将看到如下所示的同意屏幕:
![设备客户端的同意屏幕示例](https://developers.google.cn/static/identity/protocols/images/oauth2/device/approval.png?authuser=4&hl=sr)
第 6 步:处理对轮询请求的响应
Google 的授权服务器使用以下响应之一来响应每个轮询请求:
已授予权限
如果用户通过在同意屏幕上点击 Allow
授予了设备访问权限,则响应会包含一个访问令牌和一个刷新令牌。这些令牌可让您的设备代表用户访问 Google API。(响应中的 scope
属性决定了设备可以访问哪些 API。)
在这种情况下,API 响应包含以下字段:
字段 | |
---|---|
access_token |
您的应用为授权 Google API 请求而发送的令牌。 |
expires_in |
访问令牌的剩余生命周期(以秒为单位)。 |
refresh_token |
可用于获取新访问令牌的令牌。刷新令牌在用户撤消访问权限之前一直有效。请注意,系统始终会为设备返回刷新令牌。 |
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 账号无法向所请求的一个或多个范围授权。请参阅 Google Workspace 管理员帮助文章控制哪些第三方应用和内部应用可以访问 Google Workspace 数据,详细了解管理员如何限制对范围的访问权限,直至您的 OAuth 客户端 ID 明确获得访问权限。 |
invalid_client |
401 |
找不到 OAuth 客户端。例如,如果 OAuth 客户端类型不正确。确保客户端 ID 的应用类型已设置为电视和受限输入设备。 |
invalid_grant |
400 |
code 参数值无效、已被声明或无法解析。 |
unsupported_grant_type |
400 |
grant_type 参数值无效。 |
org_internal |
403 |
请求中的 OAuth 客户端 ID 属于某个项目,该项目限制对特定 Google Cloud 组织中的 Google 账号的访问权限。确认您的 OAuth 应用的用户类型配置。 |
调用 Google API
在您的应用获取访问令牌后,如果已授予某个 Google API 所需的访问权限范围,您就可以使用该令牌代表给定用户账号调用该 API。为此,请在对 API 的请求中添加访问令牌,方法是添加 access_token
查询参数或 Authorization
HTTP 标头 Bearer
值。如果可能,最好使用 HTTP 标头,因为查询字符串往往显示在服务器日志中。在大多数情况下,您可以使用客户端库来设置对 Google API 的调用(例如,在调用 YouTube Data API 时)。
请注意,YouTube Data API 仅支持拥有并管理多个 YouTube 频道的 YouTube 内容所有者(例如唱片公司和电影制片公司)的服务帐号。
您可以在 OAuth 2.0 Playground 中试用所有 Google API 并查看其范围。
HTTP GET 示例
使用 Authorization: Bearer
HTTP 标头来调用
youtube.channels
端点 (YouTube Data API) 可能如下所示。请注意,您需要指定自己的访问令牌:
GET /youtube/v3/channels?part=snippet&mine=true HTTP/1.1 Host: www.googleapis.com Authorization: Bearer access_token
以下是针对经过身份验证的用户使用 access_token
查询字符串参数对同一 API 的调用:
GET https://www.googleapis.com/youtube/v3/channels?access_token=access_token&part=snippet&mine=true
curl
个示例
您可以使用 curl
命令行应用测试这些命令。以下是使用 HTTP 标头选项的示例(首选):
curl -H "Authorization: Bearer access_token" https://www.googleapis.com/youtube/v3/channels?part=snippet&mine=true
或者,也可以使用查询字符串参数选项:
curl https://www.googleapis.com/youtube/v3/channels?access_token=access_token&part=snippet&mine=true
刷新访问令牌
访问令牌会定期过期,并成为相关 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", "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 Connect、Google 登录
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