适用于桌面应用的 OAuth 2.0

本文档介绍了桌面应用(例如在 Windows、macOS 或 Linux 上运行的应用,或命令行界面 [CLI] 工具)如何使用 Google 的 OAuth 2.0 端点来授权访问 Google API。

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

桌面应用安装在用户的本地机器上(例如独立桌面软件、开发者 CLI 工具、后台同步实用程序或脚本)。由于这些应用会分发到各个设备,因此系统会假定这些应用无法保密(它们是公共客户端)。当用户正在与应用互动或应用在后台运行时,它们可以访问 Google API。

此授权流程与用于网络服务器应用的授权流程类似。主要区别在于,桌面应用必须打开系统浏览器并提供本地重定向 URI(例如环回 IP 地址)来处理来自 Google 授权服务器的响应。

库和示例

我们建议您在为桌面应用实现 OAuth 2.0 时,使用适用于您的编程语言(例如 Python、Java、Node.js、Go、.NET)的 Google API 客户端库。客户端库会处理用户授权和令牌管理,与直接使用较低级别的 HTTP/REST 端点相比,实现起来更简单,也更不容易出错。

对于移动应用,请参阅 Android 和 iOS 授权指南。

对于在不支持系统浏览器或输入功能有限的设备(例如电视、游戏机、相机或打印机)上运行的应用,请参阅适用于电视和设备的 OAuth 2.0 或在电视和输入受限的设备上登录。

前提条件

为您的项目启用 API

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

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

  1. 在 Google API 控制台中打开 API 库。
  2. 如果系统提示您选择一个项目或创建一个新项目,请视需要选择相应选项。
  3. API 库中列出了所有可用的 API(按产品系列和热门程度分组)。 如果列表中没有显示您要启用的 API,请使用搜索功能查找该 API,或点击该 API 所属产品系列中的查看全部。
  4. 选择您要启用的 API,然后点击启用按钮。
  5. 如果系统提示,请启用结算功能。
  6. 如果系统提示您阅读并接受该 API 的服务条款,请按提示操作。

创建授权凭据

任何使用 OAuth 2.0 访问 Google API 的应用都必须具有授权凭据,以便向 Google 的 OAuth 2.0 服务器标识该应用。以下步骤介绍了如何为项目创建凭据。然后,您的应用可以使用这些凭据访问您为该项目启用的 API。

  1. 前往“客户”页面。
  2. 点击创建客户端。
  3. 选择桌面应用应用类型。
  4. 在名称字段中,输入 OAuth 客户端的名称。此名称会显示在项目的“客户端”页面上,用于标识客户端。
  5. 点击创建。

您的客户端 ID 和客户端密钥已生成,并显示在 Google Cloud 控制台中。桌面应用是公开客户端,无法对密钥保密。请求授权代码时,请始终使用 PKCE(用于代码交换的证明密钥)。

确定访问权限范围

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

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

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

获取 OAuth 2.0 访问令牌

以下步骤展示了您的应用如何与 Google 的 OAuth 2.0 服务器交互,以征得用户同意代表用户执行 API 请求。您的应用必须先获得该同意,然后才能执行需要用户授权的 Google API 请求。

第 1 步:生成代码验证器和质询

Google 支持用于代码交换的证明密钥 (PKCE) 协议,以提高安装式应用流程的安全性。系统会为每个授权请求创建一个唯一的代码验证程序,并将其转换后的值(称为“code_challenge”)发送到授权服务器,以获取授权代码。

创建代码验证器

code_verifier 是一个高熵加密随机字符串,使用非预留字符 [A-Z] / [a-z] / [0-9] / "-" / "." / "_" / "~",长度下限为 43 个字符,长度上限为 128 个字符。

代码验证器应具有足够的熵,使猜测值变得不切实际。

创建验证码

支持两种创建代码验证的方法。

代码质询生成方法
S256(推荐) 代码验证器是代码验证器的 Base64URL(无填充)编码 SHA256 哈希。
code_challenge = BASE64URL-ENCODE(SHA256(ASCII(code_verifier)))
plain 代码质询的值与上面生成的代码验证程序相同。
code_challenge = code_verifier

第 2 步:向 Google 的 OAuth 2.0 服务器发送请求

如需获取用户授权,请向 Google 的授权服务器 (https://accounts.google.com/o/oauth2/v2/auth) 发送请求。此端点会处理活跃会话查找、对用户进行身份验证,并征得用户同意。该端点只能通过 SSL 访问,并且会拒绝 HTTP(非 SSL)连接。

授权服务器支持已安装应用的以下查询字符串参数:

参数
client_id 必需

应用的客户端 ID。您可以在 Cloud 控制台的“客户端”页面中找到此值。

redirect_uri 必需

确定 Google 的授权服务器如何向您的应用发送响应。安装式应用有多个重定向选项,您需要根据特定的重定向方法设置授权凭据。

该值必须与您在客户端的 Cloud 控制台“客户端”页面中配置的 OAuth 2.0 客户端的某个已获授权的重定向 URI 完全一致。如果此值与授权 URI 不匹配,您将收到 redirect_uri_mismatch 错误。

下表显示了每种方法的相应 redirect_uri 参数值:

redirect_uri 值
自定义 URI scheme com.example.app:redirect_uri_path

或

com.googleusercontent.apps.123:redirect_uri_path
  • com.example.app 是您控制的网域的反向 DNS 表示法。自定义架构必须包含英文句点才能生效。
  • com.googleusercontent.apps.123 是客户端 ID 的反向 DNS 表示法。
  • redirect_uri_path 是可选路径组件,例如 /oauth2redirect。请注意,路径应以单个斜杠开头,这与常规 HTTP 网址不同。
环回 IP 地址 http://127.0.0.1:port 或 http://[::1]:port

在您的平台上查询相关的环回 IP 地址,并在随机可用端口上启动 HTTP 监听器。将 port 替换为应用监听的实际端口号。

请注意,移动应用对环回 IP 地址重定向选项的支持 已弃用。

response_type 必需

确定 Google OAuth 2.0 端点是否返回授权代码。

对于已安装的应用,请将参数值设置为 code。

scope 必需

以空格分隔的范围列表,用于标识您的应用可以代表用户访问的资源。这些值会告知 Google 向用户显示的权限请求页面。

借助范围,您的应用可以仅请求访问其所需的资源,同时用户也可以控制向您的应用授予的访问权限。因此,请求的范围数量与获得用户同意的可能性之间存在反比关系。

code_challenge 建议

指定一个经过编码的 code_verifier,在授权代码交换期间,它将用作服务器端质询。如需了解详情,请参阅创建代码质询。

code_challenge_method 建议

指定在授权代码交换期间将使用的 code_verifier 的编码方法。此参数必须与 code_challenge 参数搭配使用。如果包含 code_challenge 的请求中不存在 code_challenge_method,则其值默认为 plain。此参数仅支持 S256 或 plain。

state 建议

指定应用用于在授权请求与授权服务器响应之间保持状态的任何字符串值。 在用户同意或拒绝应用的访问请求后,服务器会在 redirect_uri 的网址片段标识符 (#) 中以 name=value 对的形式返回您发送的确切值。

您可以将此参数用于多种用途,例如将用户定向到应用中的正确资源、发送 Nonce 以及缓解跨站请求伪造。由于您的 redirect_uri 可能会被猜到,因此使用 state 值可以提高您对传入连接是身份验证请求结果的保证。如果您生成随机字符串或对 Cookie 的哈希值或捕获客户端状态的其他值进行编码,则可以验证响应,以额外确保请求和响应源自同一浏览器,从而防范跨站请求伪造等攻击。如需查看有关如何创建和确认 state 令牌的示例,请参阅 OpenID Connect 文档。

login_hint 可选

如果您的应用知道哪个用户正在尝试进行身份验证,则可以使用此参数向 Google 身份验证服务器提供提示。服务器会使用该提示来简化登录流程,方法是在登录表单中预填充电子邮件地址字段,或选择适当的多登录会话。

将参数值设置为电子邮件地址或 sub 标识符,这相当于用户的 Google ID。

授权网址示例

以下标签页显示了不同重定向 URI 选项的示例授权网址。

除了 redirect_uri 参数的值之外,这些网址完全相同。这些网址还包含必需的 response_type 和 client_id 参数以及可选的 state 参数。每个网址都包含换行符和空格,以便于阅读。

自定义 URI scheme

https://accounts.google.com/o/oauth2/v2/auth?
 scope=email%20profile&
 response_type=code&
 state=security_token%3D138r5719ru3e1%26url%3Dhttps%3A%2F%2Foauth2.example.com%2Ftoken&
 redirect_uri=com.example.app%3A/oauth2redirect&
 client_id=client_id

环回 IP 地址

https://accounts.google.com/o/oauth2/v2/auth?
 scope=email%20profile&
 response_type=code&
 state=security_token%3D138r5719ru3e1%26url%3Dhttps%3A%2F%2Foauth2.example.com%2Ftoken&
 redirect_uri=http%3A//127.0.0.1%3A9004&
 client_id=client_id

第 3 步:Google 提示用户表示同意

在此步骤中,用户决定是否向您的应用授予所请求的访问权限。在此阶段,Google 会显示一个权限请求窗口,其中会显示您的应用名称、应用请求使用用户的授权凭据访问的 Google API 服务,以及要授予的访问权限范围摘要。然后,用户可以同意授予对应用请求的一个或多个范围的访问权限,也可以拒绝该请求。

您的应用在此阶段无需执行任何操作,只需等待 Google 的 OAuth 2.0 服务器返回响应,指明是否已授予任何访问权限。下一步将对该响应进行说明。

错误

向 Google 的 OAuth 2.0 授权端点发出的请求可能会显示面向用户的出错提示,而不是预期的身份验证和授权流程。常见错误代码和建议的解决方法如下:

admin_policy_enforced

由于 Google Workspace 管理员的政策,Google 账号无法授权一个或多个请求的范围。请参阅 Google Workspace 管理员帮助文章 控制哪些第三方应用和内部应用可以访问 Google Workspace 数据,详细了解管理员如何限制对所有范围或敏感和受限范围的访问,直到明确向您的 OAuth 客户端 ID 授予访问权限。

disallowed_useragent

授权端点显示在 Google 的 OAuth 2.0 政策不允许的嵌入式用户代理中。

iOS 和 macOS 开发者在 WKWebView 中打开授权请求时可能会遇到此错误。 开发者应改用 iOS 库,例如 Google 登录 iOS 版或 OpenID Foundation 的 AppAuth iOS 版。

当 iOS 或 macOS 应用在嵌入式用户代理中打开常规网页链接,并且用户从您的网站导航到 Google 的 OAuth 2.0 授权端点时,Web 开发者可能会遇到此错误。开发者应允许在操作系统的默认链接处理程序中打开常规链接,这包括通用链接处理程序或默认浏览器应用。SFSafariViewController 库也是受支持的选项。

org_internal

请求中的 OAuth 客户端 ID 属于一个项目,该项目限制只有特定 Google Cloud 组织中的 Google 账号才能访问。 如需详细了解此配置选项,请参阅“设置 OAuth 权限请求页面”帮助文章中的用户类型部分。

deleted_client

用于发出请求的 OAuth 客户端已被删除。删除操作可以手动执行,也可以在客户端未使用 的情况下自动执行。已删除的客户端可在删除后的 30 天内恢复。 了解详情 。

invalid_grant

如果您使用的是代码验证器和质询,则 code_callenge 参数无效或缺失。确保 code_challenge 参数设置正确。

刷新访问令牌时,令牌可能已过期或已失效。 再次对用户进行身份验证,并征求用户同意以获取新令牌。如果您仍然看到此错误,请确保您的应用已正确配置,并且您在请求中使用了正确的令牌和参数。否则,用户账号可能已被删除或停用。

redirect_uri_mismatch

授权请求中传递的 redirect_uri 与 OAuth 客户端 ID 的授权重定向 URI 不匹配。在 Google Cloud 控制台“客户端”页面中查看已获授权的重定向 URI。

传递的 redirect_uri 可能对客户端类型无效。

redirect_uri 参数可能引用了已弃用且不再受支持的 OAuth 带外 (OOB) 流程。请参阅迁移指南,更新您的集成。

invalid_request

您发出的请求存在问题。这可能是由以下几个原因导致的:

  • 请求格式不正确
  • 请求中缺少必需参数
  • 该请求使用了 Google 不支持的授权方法。验证您的 OAuth 集成是否使用了推荐的集成方法
  • 重定向 URI 使用了不受支持的自定义架构。如果您看到出错提示 Android 应用或 Chrome 应用不支持自定义 URI scheme,请详细了解自定义 URI scheme 的替代方案。

第 4 步:处理 OAuth 2.0 服务器响应

应用接收授权响应的方式取决于其使用的重定向 URI scheme。无论采用哪种架构,响应都将包含授权代码 (code) 或错误 (error)。例如,error=access_denied 表示用户拒绝了请求。

如果用户向您的应用授予访问权限,您可以将授权代码换成访问令牌和刷新令牌,如下一步中所述。

第 5 步:将授权代码换成刷新令牌和访问令牌

如需将授权代码换成访问令牌,请调用 https://oauth2.googleapis.com/token 端点并设置以下参数:

字段
client_id 从 Cloud 控制台“客户端”页面获取的客户端 ID。
client_secret 可选

从 Cloud 控制台“客户端”页面获取的客户端密钥。

code 初始请求返回的授权代码。
code_verifier 您在第 1 步中创建的代码验证程序。
grant_type 根据 OAuth 2.0 规范中的定义,此字段的值必须设置为 authorization_code。
redirect_uri 在 Cloud 控制台“客户端”页面中为给定 client_id 列出的项目重定向 URI 之一。

虽然 DPoP 的使用是可选的,但建议使用它来提高安全性。 DPoP 的安全性依赖于私钥仅限于单个设备;我们建议以无法从设备复制的方式存储私钥,例如使用 TPM、安全隔离区或其他由硬件支持的密钥库。 如需使用 DPoP,您的应用必须为向令牌端点发出的每个请求生成一个新的唯一 DPoP 证明 JWT,并将其添加为 HTTP 请求标头。

标题 必填 说明
DPoP 可选 DPoP 证明是一个 JWT,用于证明对私钥的所有权。这是一个标头,而不是参数。如果提供,则返回的令牌会绑定到此密钥。必须为每个请求生成一个新的唯一证明,并且必须包含与请求匹配的 htm(HTTP 方法)和 htu (HTTP URI) 声明。

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

POST /token HTTP/1.1
Host: oauth2.googleapis.com
Content-Type: application/x-www-form-urlencoded
DPoP: eyJ0eXAiOiJkcG9wK2p3dCIsImFsZyI6IkVTMjU2IiwiandrIjp7Imt0eSI6Ik\
 VDIiwieCI6Imw4dEZyaHgtMzR0VjNoUklDUkRZOXpDa0RscEJoRjQyVVFVZldWQVdCR\
 nMiLCJ5IjoiOVZFNGpmX09rX282NHpiVFRsY3VOSmFqSG10NnY5VERWclUwQ2R2R1JE\
 QSIsImNydiI6IlAtMjU2In19.eyJqdGkiOiItQndDM0VTYzZhY2MybFRjIiwiaHRtIj\
 oiUE9TVCIsImh0dSI6Imh0dHBzOi8vc2VydmVyLmV4YW1wbGUuY29tL3Rva2VuIiwia\
 WF0IjoxNTYyMjYyNjE2fQ.2-GxA6T8lP4vfrg8v-FdWP0A0zdrj8igiMLvqRMUvwnQg\
 4PtFLbdLXiOSsX0x7NVY-FNyJK70nfbV37xRZT3Lg

code=4/P7q7W91a-oMsCeLvIaQm6bTrgtp7&
client_id=your_client_id&
redirect_uri=http://127.0.0.1:9004&
grant_type=authorization_code

构建 DPoP 证明

以下步骤展示了如何通过命令行使用 OpenSSL 构建 DPoP 证明:

  1. 生成 EC P-256 密钥对:
    openssl ecparam -name prime256v1 -genkey -noout -out dpop_private.pem
    openssl ec -in dpop_private.pem -pubout -out dpop_public.pem
  2. 创建 DPoP 标头:

    标头必须包含 typ、alg 和 jwk(公钥)声明。x 和 y 值是 EC 公钥的 Base64Url 编码坐标。 对以下 JSON 进行 Base64Url 编码:

    {
      "typ":"dpop+jwt",
      "alg":"ES256",
      "jwk": {
        "kty":"EC",
        "x":"YOUR_PUBLIC_KEY_X",
        "y":"YOUR_PUBLIC_KEY_Y",
        "crv":"P-256"
      }
    }
  3. 创建 DPoP 载荷:

    载荷必须包含 jti(请求的唯一标识符)、htm(HTTP 方法,例如 POST)、htu(HTTP URI,例如 https://oauth2.googleapis.com/token)和 iat(签发时间)。如果您在之前请求的响应中通过 DPoP-Nonce 标头从服务器收到了 Nonce,则必须在 nonce 声明中包含该 Nonce 值。nonce 声明对于授权代码交换是可选的,仅在之前收到 DPoP-Nonce 标头时使用。 对以下 JSON 进行 Base64Url 编码:

    {
      "jti":"JTI_VALUE",
      "htm":"POST",
      "htu":"https://oauth2.googleapis.com/token",
      "iat":YOUR_JWT_ISSUED_TIME,
      "nonce":"SERVER_PROVIDED_NONCE"
    }

    jti 值取决于广告交易平台类型:

    • 对于授权代码交换,jti 必须是授权代码的 Base64Url 编码 SHA256 哈希:"jti":"BASE64URL(SHA256(AUTHORIZATION_CODE))"。
    • 对于刷新令牌交换,jti 必须是每个请求的唯一标识符:"jti":"YOUR_UNIQUE_PER_REQUEST_IDENTIFIER"。
  4. 对证明进行签名:

    使用英文句点 (.) 拼接编码后的标头和载荷,然后使用 ES256 算法和您的私钥对结果进行签名。请注意,JWS 要求签名采用原始 R | S 串联格式(P-256 为 64 字节)。如果直接使用 OpenSSL,则必须将默认的 ASN.1 DER 编码签名转换为此原始格式。

200 OK 响应包含令牌,表示交换成功。如果在交换期间使用了有效的 DPoP 证明,Google 返回的刷新令牌将与您的密钥进行 DPoP 绑定,但访问令牌不会进行 DPoP 绑定。访问令牌将保留 Bearer 的 token_type,而不是 DPoP。此外,Google 会在响应中返回 DPoP-Nonce HTTP 标头。 您的客户端必须缓存此 Nonce,并将其包含在后续请求(例如,用刷新令牌换取新的访问令牌时,或调用受 DPoP 保护的 API 时)中 DPoP 证明的 nonce 声明中。通过使用此提前发放的 Nonce,您可以避免在下次请求时出现额外的往返失败 (use_dpop_nonce)。

对于使用 DPoP 绑定刷新令牌发出的令牌交换请求,必须包含 DPoP 证明。

如果 DPoP 标头在预期时缺失、无效,或者证明使用的密钥与绑定到令牌的密钥不同,则会发生交换失败。在这些情况下,服务器会返回 400 Bad Request 错误。 如果 DPoP 证明具有不匹配的 htm 或 htu 声明、过期的 iat、重复使用的 jti 或无效签名,Google 会返回 invalid_dpop_proof 错误代码。 如果需要 DPoP 随机数(例如在刷新令牌交换期间),并且 DPoP 证明缺少 nonce 声明,或者随机数值不被服务器接受(例如,它已过期、已被使用或不正确),Google 会返回 use_dpop_nonce 错误代码以及 DPoP-Nonce HTTP 标头,其中包含您可以在后续请求中使用的新随机数。 其他失败情况可能会返回 invalid_grant。

Google 会返回一个 JSON 对象来响应此请求,该对象包含一个短期访问令牌和一个刷新令牌。

响应包含以下字段:

字段
access_token 您的应用为授权 Google API 请求而发送的令牌。
expires_in 访问令牌的剩余生命周期(以秒为单位)。
id_token 注意:仅当您的请求包含身份范围(例如 openid、profile 或 email)时,系统才会返回此属性。该值是一个 JSON Web 令牌 (JWT),其中包含有关用户的数字签名身份信息。
refresh_token 可用于获取新访问令牌的令牌。刷新令牌在用户撤消访问权限或刷新令牌过期之前一直有效。如果使用了 DPoP,刷新令牌会绑定到用于为 DPoP 证明签名的私钥。 请注意,系统始终会为已安装的应用返回刷新令牌。
refresh_token_expires_in 刷新令牌的剩余生命周期(以秒为单位)。仅当用户授予基于时间的访问权限时,系统才会设置此值。
scope access_token 授予的访问权限范围,表示为以空格分隔、区分大小写的字符串列表。
token_type 返回的令牌类型。此值始终为 Bearer,即使使用 DPoP 也是如此。

以下代码段展示了使用 DPoP 时成功的响应标头和正文示例:

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
DPoP-Nonce: AN3XwJjZsjnb0ZuWkRlek8QU7wY-Zhf-5IP6tO0tORz0KgtDT1Bo8FX-w4nz3r5lnepI

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

第 6 步:检查用户授予了哪些范围

请求多项权限(范围)时,用户可能不会向您的应用授予所有权限。您的应用必须验证实际授予了哪些范围,并妥善处理某些权限被拒的情况,通常是停用依赖于这些被拒范围的功能。

但也有例外情况。具有全网域授权的 Google Workspace 企业版应用或标记为受信任的应用会绕过精细权限权限请求页面。对于这些应用,用户不会看到精细权限请求页面。相反,您的应用要么会获得所有请求的范围,要么一个也得不到。

如需了解详情,请参阅如何处理精细权限。

如需检查用户是否已向您的应用授予对特定范围的访问权限,请检查访问令牌响应中的 scope 字段。access_token 授予的访问权限范围,表示为以空格分隔、区分大小写的字符串列表。

例如,以下示例访问令牌响应表明,用户已向您的应用授予对只读云端硬盘活动和日历活动权限的访问权限:

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

调用 Google API

应用获取访问令牌后,如果已获得 API 所需的访问权限范围,您就可以使用该令牌代表特定用户账号调用 Google API。为此,请在向 API 发出的请求中添加访问令牌,方法是添加 access_token 查询参数或 Authorization HTTP 标头 Bearer 值。如果可能,最好使用 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 请求的无效凭证。如果您请求了对与令牌关联的范围的离线访问权限,则可以刷新访问令牌,而无需提示用户授予权限(包括在用户不在场时)。

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

名称 值
client_id 从 API 控制台获取的客户端 ID。
client_secret 可选

从 API 控制台获取的客户端密钥。 (client_secret 不适用于来自注册为 Android、iOS 或 Chrome 应用的客户端的请求。)

grant_type 如 OAuth 2.0 规范中所定义,此字段的值必须设置为 refresh_token。
refresh_token 从授权代码交换返回的刷新令牌。

虽然 DPoP 的使用是可选的,但建议使用它来提高安全性。 如需将 DPoP 与刷新令牌搭配使用,您的应用必须为向令牌端点发出的每个请求生成一个新的唯一 DPoP 证明 JWT。此证明必须使用在初始授权代码交换期间使用的同一私钥进行签名。您的应用会将证明添加为 HTTP 请求标头。

标题 必填 说明
DPoP 可选 DPoP 证明是一个 JWT,用于证明对私钥的所有权。这是一个标头,而不是参数。如果提供,则返回的令牌会绑定到此密钥。必须为每个请求生成一个新的唯一证明,并且必须包含与请求匹配的 htm(HTTP 方法)和 htu (HTTP URI) 声明。

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

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

client_id=your_client_id&
refresh_token=refresh_token&
grant_type=refresh_token

如需将 DPoP 与刷新令牌搭配使用,您必须为请求生成一个新的唯一 DPoP 证明 JWT。如需了解如何生成密钥对和构建 JWT,请参阅构建 DPoP 证明中的分步说明。

成功交换后,系统会返回 200 OK 响应,其中包含新的访问令牌。使用 DPoP 时,token_type 为 Bearer。成功的响应会确认刷新令牌的 DPoP 证明已被接受。Google 还可能会在响应中返回新的 DPoP-Nonce HTTP 标头;如果返回,您的客户端必须缓存此 Nonce,并将其包含在后续请求中 DPoP 证明的 nonce 声明中。

如果 DPoP 标头缺失、无效或使用了错误的密钥,则会发生交换失败。如需详细了解特定 DPoP 错误代码和处理 Nonce,请参阅交换失败。

以下代码段展示了使用 DPoP 时成功的响应标头和正文示例:

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
DPoP-Nonce: AN3XwJjZsjnb0ZuWkRlek8QU7wY-Zhf-5IP6tO0tORz0KgtDT1Bo8FX-w4nz3r5lnepI

{
  "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 以及错误代码。

应用重定向方法

自定义 URI scheme

自定义 URI scheme 是一种深层链接,它使用自定义 scheme 来打开您的应用。

在 Chrome 应用中使用自定义 URI scheme 的替代方案

使用 Chrome Identity API,该 API 会将 OAuth 2.0 响应直接传递给您的应用,从而无需重定向 URI。

环回 IP 地址(macOS、Linux、Windows 桌面设备)

如需使用此网址接收授权代码,您的应用必须监听本地网络服务器。许多平台都支持此功能,但并非所有平台都支持。不过,如果您的平台支持此机制,建议您使用此机制获取授权代码。

当您的应用收到授权响应时,为了获得最佳易用性,它应通过显示一个 HTML 页面来做出响应,该页面会指示用户关闭浏览器并返回到您的应用。

建议用法 macOS、Linux 和 Windows 桌面应用
表单值 将应用类型设置为桌面应用。

手动复制/粘贴(已弃用)

保护您的应用

验证 Chrome 的应用所有权

您可以验证应用的所有权,以降低应用被冒充的风险。

如需完成验证流程,您需要使用 Chrome 应用商店开发者账号。 必须满足以下要求,才能成功完成验证:

  • 您必须在 Chrome 应用商店开发者信息中心内注册一个商品,且该商品的 ID 必须与您要完成验证的 Chrome 扩展程序 OAuth 客户端的 ID 相同。
  • 您必须是 Chrome 应用商店内容的发布者。 详细了解 Chrome 应用商店开发者信息中心内的访问管理。

在 Chrome 扩展程序客户端的验证应用所有权部分中,点击验证所有权按钮以完成验证流程。

注意:授予对您账号的访问权限后,请等待几分钟,然后再完成验证流程。

如果验证成功,系统会显示一条通知,确认验证流程已成功完成。否则,系统会显示错误提示。

如需解决验证失败的问题,请尝试以下操作:

  • 确保 Chrome 应用商店开发者信息中心内有一个已注册的商品,其商品 ID 与您正在完成验证的 Chrome 扩展程序 OAuth 客户端相同。
  • 确保您是应用的发布商,即您必须是应用的个人发布商或应用群组发布商的成员。详细了解 Chrome 应用商店开发者信息中心内的访问管理。
  • 如果您刚刚更新了群组发布商列表,请验证群组发布商成员列表是否已在 Chrome 应用商店开发者信息中心内同步。 详细了解如何同步发布商成员名单。

基于时间的访问权限

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

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

延伸阅读

IETF 最佳当前实践 OAuth 2.0 for Native Apps 确立了本文档中介绍的许多最佳实践。

实现跨账号保护

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

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