- Google Ads API - 概览
- Google Ads API - 获取开发者令牌
- Google Ads API - 设置 Google API 控制台项目
- Google Ads API - 准备 Google Ads 帐号
- Google Ads API - 准备支持工具
- Google Ads API - 使用 Google OAuth 2.0 生成令牌
- Google Ads API - 调用 REST API
Google Ads API 使用 OAuth 2.0 作为授权机制。默认情况下,OAuth 2.0 身份验证会签发一个在有限时间后过期的访问令牌。要自动续订访问令牌,您应改为发出刷新令牌。
桌面应用使用 OAuth 2.0
获取 OAuth 2.0 刷新令牌
还记得之前在创建客户端 ID 和客户端密钥操作步骤中下载的 credentials.json
文件吗,我们先看一下这个 JSON 凭据文件都包含了什么内容。
json
{
"installed": {
"client_id": "******.apps.googleusercontent.com",
"project_id": "project-id-******",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://oauth2.googleapis.com/token",
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
"client_secret": "GOCSPX-w1rPm******",
"redirect_uris": [
"http://localhost"
]
}
}
我们可以利用 Google 出的 CLI 工具 oauth2l 生成刷新令牌,而 Web 应用类型的 OAuth 2.0 客户端不建议这样使用,因为你会收到 Missing code verifier
的错误信息,可参考 OAuth throws "missing code validator" in Google OAuth2 中的讨论。
下面说一下利用 oauth2l 工具获取刷新令牌的流程。
-
进入到
oauth2l
解压目录下,在终端执行以下命令:我本地是把
oauth2l
解压在D
盘的 Applications 目录下,进入该目录并执行命令。bash$ cd D:/Applications/OAuth2l $ oauth2l fetch --credentials credentials.json --scope adwords --output_format refresh_token
-
oauth2l
命令会自动在新的浏览器窗口中打开 Google 帐号登录窗口,并引导您完成 OAuth 2.0 身份验证步骤。如果您的应用未经验证,您可能会看到如下提示信息屏幕。在这种情况下,可以放心地点击继续按钮。
- 验证范围后,请点击继续按钮授予权限。
- 浏览器中会显示包含以下文本的提示:
- 回到终端,您会看到
oauth2l
命令输出以下 JSON 格式的内容
json
{
"client_id":"******.apps.googleusercontent.com",
"client_secret":"GOCSPX-w1r******",
"token_uri":"https://oauth2.googleapis.com/token",
"auth_uri":"https://accounts.google.com/o/oauth2/auth",
"refresh_token":"1//0eoRmG******",
"type":"authorized_user"
}
其中,字段 refresh_token
就是生成的刷新令牌,然后我们使用 curl 命令提取 OAuth 2.0 访问令牌。
bash
$ curl 'https://www.googleapis.com/oauth2/v3/token' \
--data 'grant_type=refresh_token' \
--data 'client_id=******.apps.googleusercontent.com' \
--data 'client_secret=GOCSPX-w1rP******' \
--data 'refresh_token=1//0eoRmG5******'
获取 OAuth 2.0 访问令牌
以下是提取 OAuth 2.0 访问令牌的响应示例:
json
{
"access_token": "ya29.a0AfB_byCl_TIukkIRHD******",
"expires_in": 3599,
"scope": "https://www.googleapis.com/auth/adwords",
"token_type": "Bearer"
}
当然,用 Postman 提取访问令牌也是可以的,如下图所示。
总结一下,我们先通过 JSON 凭据文件 credentials.json
生成 refresh_token
,再通过它提取 OAuth 2.0 access_token
。
服务端 Web 应用使用 OAuth 2.0
获取 OAuth 2.0 访问令牌
以下步骤显示了您的应用如何与 Google 的 OAuth 2.0 服务器交互,以征得用户同意以代表用户执行 API 请求。您的应用必须征得用户同意,才能执行需要用户授权的 Google API 请求。
第 1 步:设置授权参数
第一步是创建授权请求,该请求会设置一些参数来标识您的应用,并定义将要求用户向您的应用授予的权限。本教程采用直接调用 Google OAuth 2.0 端点的方式,生成一个网址并在该网址上设置参数。
Google 的 OAuth 2.0 端点位于 https://accounts.google.com/o/oauth2/v2/auth
。此端点只能通过 HTTPS 访问。普通 HTTP 连接会被拒绝。
Google 授权服务器支持 Web 服务器应用的以下查询字符串参数:
参数 | 是否必须(Y/N) | 说明 |
---|---|---|
client_id | Y | 您的应用的客户端 ID。您可以在 API Console Credentials page中找到此值。 |
redirect_uri | Y | 确定 API 服务器在用户完成授权流程后将用户重定向到何处。该值必须与 OAuth 2.0 客户端的某个已获授权的重定向 URI 完全匹配,该 URI 与您在客户端的 API Console Credentials page中配置。如果此值与提供的 client_id 的授权重定向 URI 不匹配,您会收到 redirect_uri_mismatch 错误。 请注意,http 或 https 架构、大小写以及尾随斜杠 (/ ) 必须全部匹配。 |
response_type | Y | 确定 Google OAuth 2.0 端点是否返回授权代码。 对于 Web 服务器应用,请将参数值设为 code 。 |
scope | Y | 以空格分隔的范围列表,用于标识您的应用可以代表用户访问的资源。这些值会告知 Google 向用户显示的权限请求页面。 范围可让您的应用仅请求访问所需资源,同时还允许用户控制他们向您的应用授予的访问权限大小。因此,请求的范围数量与征得用户同意的可能性之间存在反向关系。 我们建议您的应用尽可能在上下文中请求访问授权范围。通过在上下文中通过增量授权请求访问用户数据,您可以帮助用户更轻松地了解您的应用为何需要所请求的访问权限。 |
access_type | N | 推荐 指示当用户不在浏览器时,您的应用能否刷新访问令牌。有效的参数值包括 online (默认值)和 offline 。 如果您的应用需要在用户不在浏览器前刷新访问令牌,请将该值设为 offline 。这是刷新访问令牌的方法,本文档后面部分将对其进行介绍。此值指示 Google 授权服务器在您的应用首次用授权代码交换令牌时返回刷新令牌和访问令牌。 |
state | N | 推荐 指定您的应用用于维护授权请求和授权服务器响应之间的状态的任何字符串值。用户同意或拒绝您的应用的访问权限请求后,服务器返回您在 redirect_uri 的网址查询组件 (? ) 中以 name=value 对形式发送的确切值。 您可以将此参数用于多种用途,例如将用户定向到应用中的正确资源、发送 Nonce,以及减少跨网站请求伪造问题。由于您的 redirect_uri 可能会被猜到,因此使用 state 值可提高您确保传入连接是身份验证请求结果的几率。如果您生成随机字符串,或者对 Cookie 的哈希值或捕获客户端状态的其他值进行编码,则可以验证响应,以进一步确保请求和响应来自同一浏览器,从而防范跨网站请求伪造等攻击。如需查看有关如何创建和确认 state 令牌的示例,请参阅 OpenID Connect 文档。 |
include_granted_scopes | N | 允许应用在具体使用情境下使用增量授权来请求对其他范围的访问。如果您将此参数的值设置为 true ,并且授权请求获得了批准,则新的访问令牌还将涵盖用户之前授予应用访问权限的所有范围。如需查看示例,请参阅增量授权部分。 |
enable_granular_consent | N | 默认为 true 。如果设为 false ,系统将为 2019 年之前创建的 OAuth 客户端 ID 停用更精细的 Google 帐号权限。对较新的 OAuth 客户端 ID 没有任何影响,因为系统始终会为它们启用更精细的权限。 |
login_hint | N | 如果您的应用知道哪个用户正在尝试进行身份验证,它可以使用此参数向 Google 身份验证服务器提供提示。服务器会使用该提示来简化登录流程,具体方法是:在登录表单中预填充电子邮件字段,或选择适当的多登录会话。 请将此参数值设为电子邮件地址或 sub 标识符,这相当于用户的 Google ID。 |
prompt | N | 向用户显示的提示列表(以空格分隔,区分大小写)。如果您未指定此参数,则系统仅在您的项目第一次请求访问权限时提示用户。如需了解详情,请参阅提示再次同意。 可能的值包括: - none: 不显示任何身份验证或同意屏幕。不得使用其他值指定。 - consent: 提示用户同意。 - select_account: 提示用户选择帐号。 |
第 2 步:重定向到 Google 的 OAuth 2.0 服务器
将用户重定向到 Google 的 OAuth 2.0 服务器,以启动身份验证和授权流程。通常,当应用首次需要访问用户数据时,就会发生这种情况。对于增量授权,当您的应用首次需要访问其尚未有权访问的其他资源时,也会执行此步骤。
这里,我们用 Postman 工具拼接授权 URL:
Google 的 OAuth 2.0 服务器会验证用户身份,并请求用户同意您的应用访问所请求的范围。系统将使用您指定的重定向网址将响应发回给您的应用。
第 3 步:Google 提示用户同意
复制第 2 步拼接出来的授权 URL 网址到网页浏览器(如 Google Chrome)中访问,注意观察网页浏览器地址栏网址的变化。
用户会决定是否向您的应用授予请求的访问权限。在此阶段,Google 会显示一个意见征求窗口,其中会显示您的应用的名称以及它请求获得相应权限以使用用户授权凭据访问的 Google API 服务,并简要说明要授予的访问权限范围。然后,用户可以同意向您的应用请求的一个或多个范围授予访问权限,或拒绝该请求。
在此阶段,您的应用无需执行任何操作,因为它会等待 Google 的 OAuth 2.0 服务器做出指示是否已授予任何访问权限的响应。
第 4 步:处理 OAuth 2.0 服务器响应
OAuth 2.0 服务器使用请求中指定的网址来响应您应用的访问请求。
如果用户批准了访问请求,响应中就会包含授权代码。如果用户未批准该请求,响应中将包含错误消息。返回给网络服务器的授权代码或错误消息会显示在查询字符串中,如下表所示:
响应 | 示例 |
---|---|
错误响应 | oauth.pstmn.io/v1/callback... |
授权代码响应 | oauth.pstmn.io/v1/callback... |
下图就为我们展示了一个授权成功的示例,可以看到在完成 OAuth 2.0 流程后,系统会将您重定向至 https://www.googleapis.com/auth/adwords
。其实中的 code
的值就是用户被重定向回应用时 URI 中返回的授权码。
第 5 步:用授权码来刷新令牌和访问令牌
收到授权码后就可以使用它换取访问令牌。要将授权代码换成访问令牌,请调用 https://oauth2.googleapis.com/token
API 并设置以下参数:
请求参数 | 是否必传 | 说明 |
---|---|---|
client_id |
Y | 从 API Console Credentials page 中获取的客户端 ID。 |
client_secret |
Y | 从 Credentials page API Console获得的客户端密钥。 |
code |
Y | 初始请求返回的授权代码,即 code 对应的值。 |
grant_type |
Y | 根据 OAuth 2.0 规范的定义,此字段的值必须设置为 authorization_code 。 |
redirect_uri |
Y | 在给定 client_id 的 API Console Credentials page 中为您的项目列出的某个重定向 URI。 |
下图是我用 Postman 发起一个 POST
请求示例:
注意 :从浏览器地址栏复制出来的
code
中大部分情况下会含有转义符%2F
,将其还原为反斜杠/
。否则会报如下错误:
json{ "error": "invalid_grant", "error_description": "Malformed auth code." }
Google 通过返回一个 JSON 对象来响应此请求,该对象包含一个短期有效的访问令牌和一个刷新令牌。 请注意,只有当您的应用在[向 Google 授权服务器发出的初始请求](#向 Google 授权服务器发出的初始请求 "#heading-3")中将 access_type
参数设置为 offline
时,系统才会返回刷新令牌。
响应包含以下字段:
字段 | 说明 |
---|---|
access_token |
您的应用发送的令牌,用于向 Google API 请求授权。 |
expires_in |
访问令牌的剩余生命周期(以秒为单位)。 |
refresh_token |
可用于获取新访问令牌的令牌。刷新令牌在用户撤消访问权限之前一直有效。 同样,只有当您在向 Google 授权服务器发送的初始请求中将 access_type 参数设为 offline 时,此字段才会出现在此响应中。 |
scope |
access_token 授予的访问权限范围,表示为以空格分隔且区分大小写的字符串列表。 |
token_type |
返回的令牌类型。目前,此字段的值始终设置为 Bearer 。 |
以下代码段显示了一个示例响应:
json
{
"access_token": "ya29.a0AfB_byCuhQ1Em8wf2UHBjFvNjAFNM",
"expires_in": 3599,
"refresh_token": "1//0eTjQu9xHQV6BCgYIARAAGA4SNwF-L9",
"scope": "https://www.googleapis.com/auth/adwords",
"token_type": "Bearer"
}
错误码
当用授权代码交换访问令牌时,您可能会遇到以下错误(而不是预期响应)。下面列出了常见的错误代码和建议的解决方案。
错误码 | 失败原因 | 解决方案 |
---|---|---|
invalid_grant |
提供的授权代码无效或格式错误 | 通过[重启 OAuth 流程](#错误码 失败原因 解决方案 invalid_grant 提供的授权代码无效或格式错误 通过重启 OAuth 流程请求新的授权码,再次提示用户同意。 "#heading-4")请求新的授权码,再次提示用户同意。 |
当然,在您成功拿到 OAuth 2.0 访问令牌后,如果用 Postman 再次提交该请求,你会发现响应也会报如下所示的 invalid_grant
类型错误,这是因为 code
仅一次有效,同样利用上面提到的解决方案去重新请求授权码。
json
{
"error": "invalid_grant",
"error_description": "Bad Request"
}
刷新访问令牌(离线访问)
访问令牌会定期过期,会使得相关 API 请求失败。如果您请求离线访问与令牌相关联的范围,则可以刷新访问令牌,而不提示用户授予权限(包括用户不存在时)。
这就需要您在[将用户重定向到 Google 的 OAuth 2.0 服务器](#将用户重定向到 Google 的 OAuth 2.0 服务器 "#heading-6")时,将 access_type
参数设置为 offline
。在这种情况下,当您用授权代码换取访问令牌时,Google 的授权服务器会返回一个刷新令牌。然后,如果访问令牌到期,您可以使用刷新令牌来获取新的访问令牌。
对于任何需要在用户不在场时访问 Google API 的应用,均需请求离线访问。例如,在预定时间执行备份服务或执行操作的应用需要能够在用户不在场时刷新其访问令牌。默认的访问权限样式称为 online
。
服务器端 Web 应用、已安装的应用和设备都会在授权过程中获取刷新令牌。刷新令牌通常不用于客户端 (JavaScript) Web 应用。
如需刷新访问令牌,您的应用会向 Google 的授权服务器 (https://oauth2.googleapis.com/token
) 发送 HTTPS POST
请求,其中包含以下参数:
字段 | 是否必须 | 说明 |
---|---|---|
client_id |
Y | 从 API Console 获得的客户端 ID。 |
client_secret |
Y | 从 API Console 获得的客户端密钥。 |
grant_type |
Y | 根据 OAuth 2.0 规范中的定义,此字段的值必须设置为 refresh_token 。 |
refresh_token |
Y | 通过授权码交换返回的刷新令牌。 |
以下代码段展示了一个示例请求:
http
POST /token HTTP/1.1
Host: oauth2.googleapis.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 279
client_id=******.apps.googleusercontent.com&
client_secret=GOCSP******&
grant_type=refresh_token&
refresh_token=1%2F%******
只要用户没有撤消授予应用的访问权限,令牌服务器就会返回一个包含新访问令牌的 JSON 对象。以下代码段显示了一个示例响应:
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
发出请求,并将该令牌作为参数包含在内:
http
POST /revoke HTTP/1.1
Host: oauth2.googleapis.com
Content-type: application/x-www-form-urlencoded
token=ya29.a0AfB******
该令牌可以是访问令牌,也可以是刷新令牌。如果该令牌是访问令牌,并且它具有相应的刷新令牌,则该刷新令牌也会被撤消。
以下是用 Postman 撤销访问令牌的请求示例:
如果撤消处理成功,则响应的 HTTP 状态代码为 200
。对于错误情况,系统会返回 HTTP 状态代码 400
以及错误代码。当然,撤消成功响应后,撤消可能需要一些时间才能完全生效。