适用于电视和受限输入设备应用程序的OAuth 2.0

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

OAuth 2.0允许用户与应用程序共享特定数据,同时将用户名,密码和其他信息保密。例如,电视应用程序可以使用OAuth 2.0获得选择存储在Google云端硬盘上的文件的权限。

由于使用此流程的应用程序已分发到各个设备,因此假定这些应用程序无法保存机密。当用户出现在应用程序中或应用程序在后台运行时,他们可以访问Google API。

备择方案

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

先决条件

为您的项目启用API

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

为您的项目启用API:

  1. Google API Console中的Open the API Library
  2. If prompted, select a project, or create a new one.
  3. API Library列出了所有可用的API,并按产品系列和受欢迎程度分组。如果您要启用的API在列表中不可见,请使用搜索找到它,或单击其所属产品系列中的“查看全部”。
  4. 选择要启用的API,然后单击“启用”按钮。
  5. If prompted, enable billing.
  6. If prompted, read and accept the API's Terms of Service.

创建授权凭证

使用OAuth 2.0访问Google API的任何应用程序都必须具有授权凭据,以将应用程序标识到Google的OAuth 2.0服务器。以下步骤说明了如何为您的项目创建凭据。然后,您的应用程序可以使用凭据来访问为该项目启用的API。

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

确定访问范围

范围使您的应用程序仅可以请求访问其所需的资源,同时还使用户能够控制他们授予您的应用程序的访问量。因此,请求的范围数与获得用户同意的可能性之间可能存在反比关系。

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

有关已安装的应用程序或设备,请参阅“允许的范围”列表。

获取OAuth 2.0访问令牌

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

  1. 您的应用程序向Google的授权服务器发送了一个请求,该请求标识了您的应用程序将请求访问权限的范围。
  2. 服务器以后续步骤中使用的几条信息作为响应,例如设备代码和用户代码。
  3. 您显示用户可以在单独的设备上输入以授权您的应用程序的信息。
  4. 您的应用程序开始轮询Google的授权服务器,以确定用户是否已授权您的应用程序。
  5. 用户切换到具有更丰富输入功能的设备,启动Web浏览器,导航到步骤3中显示的URL,然后输入也在步骤3中显示的代码。然后,用户可以授予(或拒绝)对您的应用程序的访问。
  6. 对轮询请求的下一个响应包含您的应用代表用户授权请求所需的令牌。 (如果用户拒绝访问您的应用程序,则响应中不包含令牌。)

下图说明了此过程:

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

以下各节详细说明了这些步骤。给定设备可能具有的功能范围和运行时环境,本文档中显示的示例使用curl命令行实用程序。这些示例应该易于移植到各种语言和运行时。

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

在此步骤中,您的设备通过https://oauth2.googleapis.com/device/code将HTTP POST请求发送到Google的授权服务器,该请求可识别您的应用程序以及您的应用程序要在用户的设备上访问的访问范围代表。您应该使用device_authorization_endpoint元数据值从“发现”文档中检索此URL。包括以下HTTP请求参数:

参数
client_id必需的

您的应用程序的客户端ID。您可以在API Console Credentials page中找到该值。

scope必需的

用空格分隔的范围列表,这些范围标识应用程序可以代表用户访问的资源。这些值通知Google向用户显示的同意屏幕。有关已安装的应用程序或设备,请参阅“允许的范围”列表。

范围使您的应用程序仅可以请求访问其所需的资源,同时还使用户能够控制他们授予您的应用程序的访问量。因此,在所请求范围的数量与获得用户同意的可能性之间存在反比关系。

例子

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

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

client_id=client_id&scope=email%20profile

此示例显示了curl命令以发送相同的请求:

curl -d "client_id=client_id&scope=email%20profile" \
     https://oauth2.googleapis.com/device/code

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

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

成功回应

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

特性
device_code Google唯一分配的一个值,用于标识运行请求授权的应用的设备。用户将从具有更丰富输入功能的另一台设备授权该设备。例如,用户可能使用笔记本电脑或移动电话来授权在电视上运行的应用。在这种情况下, device_code标识电视。

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

expires_in device_codeuser_code有效的时间长度(以秒为单位)。如果在那个时候用户没有完成授权流程,并且您的设备也没有轮询来检索有关用户决定的信息,那么您可能需要从步骤1重新开始此过程。
interval您的设备应在两次轮询请求之间等待的时间长度(以秒为单位)。例如,如果值为5 ,则您的设备应每五秒钟向Google授权服务器发送一次轮询请求。有关更多详细信息,请参见步骤3
user_code区分大小写的值,用于向Google标识应用程序请求访问的范围。您的用户界面将指示用户在具有更丰富输入功能的单独设备上输入此值。然后,当提示用户授予对您的应用程序的访问权限时,Google使用该值显示正确的范围集。
verification_url用户必须在单独的设备上导航到的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

在设计用户界面(UI)时,请牢记以下规则:

  • user_code
    • 用户user_code必须显示在可以处理15个“ W”尺寸字符的字段中。换句话说,如果您可以正确显示代码WWWWWWWWWWWWWWW ,则您的用户界面是有效的,我们建议您在测试user_code在用户界面中的显示方式时使用该字符串值。
    • user_code区分大小写,不应以任何方式进行修改,例如更改大小写或插入其他格式字符。
  • verification_url
    • 显示verification_url的空间必须足够宽,以处理40个字符长的URL字符串。
    • 除了有选择地删除显示方案之外,您不应以任何方式修改verification_url 。如果出于显示的原因确实打算从URL中删除该方案(例如https:// ),请确保您的应用程序可以同时处理httphttps变体。

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

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

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

要轮询的端点的URL为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" \
         /token

步骤5:用户响应访问请求

下图显示了一个页面,该页面类似于用户导航到您在步骤3中显示的verification_url时所看到的页面:

通过输入代码连接设备

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

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

步骤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"
}

其他错误

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

错误HTTP状态码描述
invalid_client 401找不到OAuth客户端。例如,如果client_id参数值无效,则会发生此错误。
invalid_grant 400 code参数值无效。
unsupported_grant_type 400 grant_type参数值无效。

调用Google API

您的应用程序获取访问令牌后,如果已授予该API所需的访问范围,则可以使用该令牌代表给定的用户帐户对Google API进行调用。为此,请通过包含access_token查询参数或Authorization HTTP标头Bearer值,在对API的请求中包含访问令牌。尽可能使用HTTP标头,因为查询字符串在服务器日志中趋于可见。在大多数情况下,您可以使用客户端库来设置对Google API的调用(例如,在调用Drive Files API时)。

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

HTTP GET示例

使用Authorization: Bearer HTTP标头对drive.files端点(Drive Files API)的调用可能类似于以下内容。请注意,您需要指定自己的访问令牌:

GET /drive/v2/files HTTP/1.1
Host: www.googleapis.com
Authorization: Bearer access_token

这是使用access_token查询字符串参数为已认证用户调用相同API的命令:

GET https://www.googleapis.com/drive/v2/files?access_token=access_token

curl例子

您可以使用curl命令行应用程序测试这些命令。这是使用HTTP标头选项(首选)的示例:

curl -H "Authorization: Bearer access_token" https://www.googleapis.com/drive/v2/files

或者,或者查询字符串参数选项:

curl https://www.googleapis.com/drive/v2/files?access_token=access_token

刷新访问令牌

访问令牌会定期过期,并成为相关API请求的无效凭据。如果您请求脱机访问与令牌关联的范围,则可以刷新访问令牌而无需提示用户许可(包括当用户不存在时)。

要刷新访问令牌,您的应用程序将HTTPS POST请求发送到Google的授权服务器( https://oauth2.googleapis.com/token ),该请求包含以下参数:

领域
client_idAPI Console获得的客户端ID。
client_secretAPI 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 ConnectGoogle登录

  • email
  • openid
  • profile

云端硬盘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