互联网草案 OAuth 2.1 授权框架 2026 年 9 月
Hardt 等人 2027 年 3 月 7 日到期 [页]
工作组:
OAuth 工作组
互联网草案:
draft-ietf-oauth-v2-1-16
发布于:
预期状态:
标准轨道
到期:
作者:
D. Hardt
Hellō
A. Parecki
Okta
T. Lodderstedt
SPRIND

OAuth 2.1 授权框架

摘要

OAuth 2.1 授权框架使 应用程序能够获得对受保护资源的有限访问权限,可以 代表资源所有者,通过协调资源所有者 与授权服务之间的批准交互来实现,也可以允许 应用程序代表自身获得访问权限。此 规范取代并废止 RFC 6749 中描述的 OAuth 2.0 授权 框架以及 RFC 6750 中的持有者令牌用法。

讨论渠道

此注释将在作为 RFC 发布之前删除。

有关本文档的讨论在 OAuth 工作组邮件列表(oauth@ietf.org)上进行, 其存档位于 https://mailarchive.ietf.org/arch/browse/oauth/。

此草案的源文件和问题跟踪器可在 https://github.com/oauth-wg/oauth-v2-1 找到。

本备忘录的状态

本互联网草案的提交完全符合 BCP 78 和 BCP 79 的规定。

互联网草案是互联网工程任务组 (IETF)的工作文档。请注意,其他组织也可能将工作 文档作为互联网草案发布。当前互联网草案的列表 位于 https://datatracker.ietf.org/drafts/current/。

互联网草案是有效期最长为六个月的草案文档, 并且随时可能被其他文档更新、替代或废止。 不宜将互联网草案用作参考 材料,或以“进行中的工作”之外的方式引用它们。

本互联网草案将于 2027 年 3 月 7 日到期。

▲

目录

1. 简介

OAuth 通过将客户端的角色与资源 所有者的角色分离,为客户端-服务器认证模型引入了授权层。 在 OAuth 中,客户端请求访问由资源所有者控制并 托管在资源服务器上的资源。 客户端不使用资源所有者的凭据访问受保护的 资源,而是获取访问令牌——一种表示 一组特定访问属性(例如作用域和生命周期)的凭据。访问 令牌由授权服务器在获得资源所有者批准后颁发给客户端。 客户端使用访问令牌访问托管在资源服务器上的 受保护资源。

在较旧、功能更有限的客户端-服务器认证模型中,客户端 通过使用资源所有者的 凭据向服务器进行认证,来请求服务器上的受限访问资源 (受保护资源)。为了让应用程序能够访问 受限资源,资源所有者会与应用程序共享其凭据。 这会造成若干问题和限制:

OAuth 的一个使用示例是:最终用户(资源所有者)授予某个财务 管理 服务(客户端)访问存储在银行服务(资源服务器)中的 敏感交易历史的权限,而无需与该财务管理服务共享其用户名和 密码。相反,用户直接向其金融机构的服务器 (授权服务器)进行认证, 该服务器会向财务管理服务颁发特定于委托的凭据 (访问令牌)。

这种关注点分离还使得能够使用更高级的 用户认证方法,例如多因素认证,甚至是 无密码认证,而无需对应用程序进行任何修改。 由于所有用户认证逻辑都由授权服务器处理, 应用程序无需关心实现 任何特定认证机制的具体细节。这使 授权服务器能够管理用户认证策略,并且 甚至可以在将来更改这些策略,而无需与应用程序协调这些更改。

授权层还可以简化资源服务器确定 请求是否已获授权的方式。传统上,在客户端完成认证后, 每个资源服务器都会评估策略,以计算客户端在每次 API 调用中是否被授权。 在分布式系统中,这些策略需要同步到 所有资源服务器,或者资源服务器必须调用中央策略 服务器来处理每个请求。在 OAuth 中,仅当授权服务器创建 新的访问令牌时才会评估策略。如果 已授权的访问权限体现在访问令牌中,资源服务器便不再 需要评估策略,而只需验证访问令牌。 无论应用程序是代表资源 所有者执行操作,还是代表自身执行操作,都适用这种简化方式。

OAuth 是一种授权协议,而不是认证协议,因为 OAuth 并未 定义实现用户认证所必需的组件。 如果目标是认证用户,则必须使用认证协议。一个示例是 OpenID Connect [OpenID.Connect],它构建于 OAuth 之上,以提供认证协议所需的安全 特性和必要组件。

访问令牌表示授予客户端的授权。客户端通常会 将访问令牌提交给专有 API,该 API 返回资源所有者的用户标识符,然后将该 API 的结果作为认证用户的替代方式。这种做法不属于 OAuth 标准或其安全注意事项的一部分,并且资源所有者可能并未 考虑到这一点。实现者在采用这种做法之前应该仔细查阅 资源服务器的文档。

本规范设计用于 HTTP [RFC9110]。在 HTTP 以外的任何协议上使用 OAuth 均超出本规范的范围。

自 OAuth 2.0 授权框架 [RFC6749] 于 2012 年 10 月发布以来,它已由原生应用的 OAuth 2.0 [RFC8252]、 OAuth 安全最佳当前实践 [RFC9700] 以及基于浏览器的应用的 OAuth 2.0 [I-D.ietf-oauth-browser-based-apps] 更新。 OAuth 2.0 授权框架:持有者令牌用法 [RFC6750] 也已由 [RFC9700] 更新。本 标准轨道规范整合了所有这些 文档中的信息,并移除了在 [RFC9700] 中被认定为不安全的功能。

1.1. 角色

OAuth 定义了四种角色:

“资源所有者”:

能够授予对受保护资源访问权限的实体。 当资源所有者是个人时,将其称为 最终用户。有时缩写为“RO”。

“资源服务器”:

托管受保护资源的服务器,能够使用访问令牌 接受并响应受保护资源请求。 资源服务器通常可通过 API 访问。 有时缩写为“RS”。

“客户端”:

代表资源所有者并经其授权而发出受保护资源请求的 应用程序。“客户端”一词并不 暗示任何特定的实现特征(例如, 应用程序是在服务器、桌面设备还是其他 设备上执行)。

“授权服务器”:

在成功认证资源所有者并获得授权后 向客户端颁发访问令牌的服务器。 有时缩写为“AS”。

本规范的大部分内容定义了客户端 与授权服务器之间的交互,以及客户端与资源服务器之间的交互。

授权服务器与资源服务器之间的交互 超出本规范的范围,不过已经定义了若干扩展,以 提供资源服务器与授权服务器之间实现互操作性的选项。 授权服务器可以与资源服务器位于同一服务器上,也可以是单独的实体。 单个授权服务器可以颁发由 多个资源服务器接受的访问令牌。

资源所有者与授权服务器之间的交互 (例如最终用户如何在授权服务器上认证自身) 同样超出本规范的范围,但也存在一些例外,例如 围绕提示最终用户同意的安全注意事项。

当资源所有者是最终用户时,用户将与 客户端交互。当客户端是基于 Web 的应用程序时,用户将 通过用户代理与客户端交互(如 第 3.5 节( [RFC9110])所述)。 当客户端是原生应用程序时,用户将通过操作系统 直接与客户端交互。有关更多详细信息,请参阅第 2.1 节。

1.2. 协议流程

     +--------+                               +---------------+
     |        |--(1)------ 授权请求 --------->|    资源       |
     |        |                               |    所有者      |
     |        |<-(2)------ 授权许可 ---------|               |
     |        |                               +---------------+
     |        |
     |        |                               +---------------+
     |        |--(3)------ 授权许可 -------->|     授权      |
     | 客户端  |                               |     服务器     |
     |        |<-(4)------ 访问令牌 ---------|               |
     |        |                               +---------------+
     |        |
     |        |                               +---------------+
     |        |--(5)------ 访问令牌 -------->|     资源      |
     |        |                               |     服务器     |
     |        |<-(6)------ 受保护资源 -------|               |
     +--------+                               +---------------+
图 1: 抽象协议流程

图 1中所示的抽象 OAuth 2.1 流程描述了 四种角色之间的交互,并包括以下步骤:

  1. 客户端向资源所有者请求授权。 授权请求可以直接向资源所有者发出 (如图所示),也可以并且最好通过作为中介的授权 服务器间接发出。

  2. 客户端接收授权许可,它是一种 表示资源所有者授权的凭据, 使用本规范定义的某种授权许可类型 或扩展许可类型表示。 授权许可类型取决于客户端 请求授权所使用的方法以及授权服务器支持的类型。

  3. 客户端通过向授权服务器进行认证并 提交授权许可来请求访问令牌。

  4. 授权服务器认证客户端并验证 授权许可,如果有效,则颁发访问令牌。

  5. 客户端向资源服务器请求受保护资源, 并通过提交访问令牌进行认证。

  6. 资源服务器验证访问令牌,如果有效, 则处理该请求。

客户端从资源所有者获取授权许可 (步骤 (1) 和 (2) 所示)的首选方法是使用 授权服务器作为中介,如 第 4.1 节中的 图 3所示。

1.3. 授权许可

授权许可表示资源 所有者的授权(访问其受保护资源),客户端使用它来 获取访问令牌。本规范定义了三种 许可类型——授权码、刷新令牌 和客户端凭据——以及用于定义其他类型的 可扩展机制。

1.3.1. 授权码

授权码是一种用于获取 访问令牌的临时凭据。 客户端不会 直接向资源所有者请求授权,而是将 资源所有者引导至授权服务器(通过其 用户代理),授权服务器随后携带授权码将 资源所有者引导回客户端。 客户端随后可以用授权码交换访问令牌。

在携带授权码将资源所有者引导回客户端之前, 授权服务器会认证 资源所有者,并且可以请求资源所有者同意,或者以其他方式 告知其客户端的请求。由于资源所有者 只与授权服务器进行认证,因此资源 所有者的凭据永远不会与客户端共享,并且客户端 无需了解任何额外的认证步骤, 例如多因素认证或委托账户。

授权码提供了若干重要的安全优势, 例如能够认证客户端,以及 将访问令牌直接传输给客户端,而无需 通过资源所有者的用户代理传递,从而避免可能 将其暴露给其他方,包括资源所有者。

1.3.2. 刷新令牌

刷新令牌是用于获取访问令牌的凭据。刷新 令牌可以由授权服务器颁发给客户端,并 用于在当前访问令牌 失效或过期时获取新的访问令牌,或者获取 作用域相同或更窄的其他访问令牌(访问令牌可以具有比资源 所有者所授权的更短生命周期和更少 权限)。是否颁发刷新令牌由 授权服务器自行决定,是可选的,并且可以基于客户端的属性、 请求的属性、授权服务器内部的策略或 任何其他标准。如果授权服务器颁发刷新 令牌,则会在颁发访问令牌时将其一并包含(即 图 2中的步骤 (2))。刷新令牌的生命周期同样 由授权服务器自行决定。

刷新令牌是表示资源所有者授予 客户端的授权的字符串。对于 客户端而言,该字符串被视为不透明值。刷新令牌可以是用于检索 授权信息的标识符,也可以将这些信息编码到 字符串本身中。与访问令牌不同,刷新令牌 仅供授权服务器使用,绝不会发送 给资源服务器。

+--------+                                           +---------------+
|        |--(1)---------- 授权许可 ----------------->|               |
|        |                                           |               |
|        |<-(2)---------- 访问令牌 -----------------|               |
|        |               & 刷新令牌                 |               |
|        |                                           |               |
|        |                            +----------+   |               |
|        |--(3)---- 访问令牌 -------->|          |   |               |
|        |                            |          |   |               |
|        |<-(4)--- 受保护资源 --------|   资源   |   |     授权      |
| 客户端 |                            |   服务器  |   |     服务器     |
|        |--(5)---- 访问令牌 -------->|          |   |               |
|        |                            |          |   |               |
|        |<-(6)--- 无效令牌错误 ------|          |   |               |
|        |                            +----------+   |               |
|        |                                           |               |
|        |--(7)---------- 刷新令牌 ----------------->|               |
|        |                                           |               |
|        |<-(8)---------- 访问令牌 -----------------|               |
+--------+           & 可选刷新令牌                  +---------------+
图 2: 刷新 已过期的访问令牌

图 2中所示的流程包括以下步骤:

  1. 客户端通过向 授权服务器进行认证并提交授权许可来请求访问令牌。

  2. 授权服务器认证客户端并 验证授权许可,如果有效,则颁发访问令牌 以及可选的刷新令牌。

  3. 客户端通过向资源 服务器提交访问令牌来发出受保护资源请求。

  4. 资源服务器验证访问令牌,如果 有效,则处理请求。

  5. 重复步骤 (3) 和 (4),直到访问令牌过期。 如果 客户端知道访问令牌已过期,则跳到步骤 (7); 否则,它会再次发出受保护资源请求。

  6. 由于访问令牌无效,资源服务器 返回无效令牌错误。

  7. 客户端通过提交刷新令牌 请求新的访问令牌,并且如果已向其颁发凭据,则提供客户端认证。 客户端认证要求基于客户端类型 以及授权服务器策略。

  8. 授权服务器认证客户端并 验证刷新令牌,如果有效,则颁发新的访问令牌(以及 可选的新刷新令牌)。

请注意,无需将刷新 令牌的生命周期告知客户端,因为即使客户端知道 该生命周期,也无法采取不同的操作。此外,授权服务器 可能选择使用动态生命周期(例如,只要刷新令牌至少每 7 天使用一次, 就延长刷新令牌的到期时间), 或者授权服务器可能出于任何原因在 计划到期日期之前撤销刷新令牌,例如用户 撤销应用程序的访问权限。这意味着客户端本来就必须 处理刷新令牌在任意时间到期的情况。

无论刷新令牌为何或何时过期,客户端 都只有一种获取新令牌的途径,即从头开始新的 OAuth 流程。因此,没有定义任何 用于向客户端传达刷新令牌过期时间的属性。

1.3.3. 客户端凭据

当授权作用域仅限于 客户端控制的受保护资源, 或仅限于此前已与授权服务器安排好的受保护资源时, 客户端凭据或其他形式的客户端认证 (例如用于签署 JWT 的私钥,如 [RFC7523] 及其更新 [I-D.ietf-oauth-rfc7523bis] 中所述) 可以用作授权许可。客户端凭据用于客户端根据 先前与授权服务器安排好的授权请求 访问受保护资源的情况。

1.4. 访问令牌

访问令牌是用于访问受保护资源的凭据。 访问令牌是表示颁发给 客户端的授权的字符串。

即使该字符串具有 某种结构,对于客户端而言也被视为不透明值。客户端不得期望能够解析访问 令牌的值。除了资源服务器所 预期的编码或格式之外,授权服务器无需对 访问令牌使用一致的编码或格式。

资源所有者授予客户端的访问权限由 授权服务器创建的访问令牌表示。访问令牌 的生命周期较短,以减小访问令牌泄露后的影响范围。访问 令牌的到期时间由授权服务器设置。

根据授权服务器的实现方式, 资源服务器可以使用令牌字符串检索授权信息, 也可以让令牌以可验证的方式自身包含授权信息 (即,由已签名的数据负载组成的令牌字符串)。令牌检索机制的一个示例 是令牌内省 [RFC7662],其中 RS 调用 AS 上的端点来验证客户端提交的令牌。 结构化令牌格式的一个示例是访问令牌的 JWT 配置文件 [RFC9068], 它是一种将访问令牌数据编码并签署为 JSON Web Token [RFC7519] 的方法。

为了让客户端使用访问令牌, 可能还需要本规范范围之外的额外认证凭据。 这通常称为发送方约束的 访问令牌,例如 DPoP [RFC9449] 和 绑定相互 TLS 证书的访问令牌 [RFC8705]。

访问令牌提供了一个抽象层,将不同的 授权构造(例如用户名和密码)替换为资源服务器能够理解的单个 令牌。这种抽象使得 可以颁发比用于获取访问令牌的授权许可 限制更多的访问令牌,同时也消除了资源服务器 理解大量认证方法的需要。

访问令牌可以根据资源 服务器的安全要求采用不同的格式、结构和 使用方法(例如密码学属性)。访问令牌属性以及 用于访问受保护资源的方法可以扩展到 本规范所述内容之外。

访问令牌(以及任何机密的访问令牌 属性)在传输和存储过程中必须保持机密,并且 只能在授权服务器、该访问令牌对其有效的资源服务器 以及该访问令牌所颁发给的客户端之间共享。

授权服务器必须确保未经授权的参与方无法 生成、修改或猜测出有效的访问令牌。

1.4.1. 访问令牌作用域

访问令牌旨在向客户端颁发比 授予访问权限的用户所拥有权限更少的 权限。这称为具有有限“作用域”的 访问令牌。授权服务器和资源服务器可以使用这种 作用域机制来限制特定客户端可以访问哪些类型的资源或具有何种访问级别。

例如,客户端可能只需要对用户 资源的“读取”访问权限,而不需要更新资源,因此客户端可以请求 授权服务器定义的只读作用域,并获取 无法用于更新资源的访问令牌。这需要 授权服务器、资源服务器和客户端之间进行协调。授权 服务器使客户端能够请求特定 作用域,并将这些作用域与颁发给客户端的访问令牌相关联。 然后,资源服务器负责在收到 有限作用域访问令牌时实施相应的作用域限制。

OAuth 不定义任何作用域值,而是由 授权服务器、OAuth 的扩展或配置文件来定义作用域。定义作用域的一个此类扩展 是 [OpenID.Connect],它定义了一组 可提供对用户个人资料信息细粒度访问的作用域。 建议避免定义与已知扩展中的作用域相冲突的自定义作用域。

为了请求有限作用域的访问令牌,客户端根据 所使用的许可类型,在授权端点或令牌端点使用 scope 请求参数。相应地,授权服务器使用 scope 响应参数告知客户端所颁发访问令牌的作用域。

scope 参数的值表示为空格分隔的 区分大小写的字符串列表。这些字符串由 授权服务器定义。如果该值包含多个由空格分隔的 字符串,它们的顺序无关紧要,并且每个字符串都会为请求的作用域 增加一个额外的访问范围。

    scope       = scope-token *( SP scope-token )
    scope-token = 1*( %x21 / %x23-5B / %x5D-7E )

授权服务器可以根据授权服务器策略或 资源所有者的指示,完全或部分忽略客户端请求的作用域。 如果所颁发访问令牌的作用域 与客户端请求的作用域不同,授权 服务器必须在令牌响应 (第 3.2.3 节)中包含 scope 响应参数,以告知 客户端实际授予的作用域。

如果客户端在请求授权时省略 scope 参数, 授权服务器必须使用预定义的默认值处理 请求,或者让请求失败并指明作用域无效。 授权服务器应该记录其作用域要求和默认值(如果已定义)。

1.4.2. 持有者令牌

持有者令牌是一种安全令牌,其属性是任何 持有该令牌的参与方(“持有者”)都能以 任何其他持有该令牌的参与方可以使用的方式使用该令牌。使用持有者令牌 不要求持有者证明其拥有密码学密钥材料 (持有证明)。

持有者令牌可以通过持有证明 规范得到增强,例如 DPoP [RFC9449] 和 mTLS [RFC8705],从而提供 持有证明特性。

为了防止访问令牌泄露, 客户端与资源服务器之间的通信交互 必须使用第 1.5 节所述的 机密性和完整性保护。

持有者令牌的具体结构或格式没有要求。 如果持有者令牌是对授权信息的引用,则攻击者必须无法实际 猜出此类引用,例如使用足够长的 密码学随机字符串。如果持有者令牌使用编码机制将 授权信息包含在令牌本身中,则访问令牌必须使用 足以防止令牌被修改的完整性保护。访问令牌的 一种编码和签名机制在访问令牌的 JSON Web Token 配置文件 [RFC9068] 中进行了说明。

1.4.3. 发送方约束的访问令牌

发送方约束的访问令牌会将 访问令牌的使用绑定到特定发送方。该发送方必须 证明其知道某个秘密,作为接收方 (例如资源服务器)接受该访问令牌的前提条件。

授权服务器和资源服务器应该使用用于 对访问令牌施加发送方约束的机制,例如 OAuth 持有证明演示 (DPoP)[RFC9449] 或 OAuth 2.0 的相互 TLS [RFC8705]。 有关防止被盗和泄露的 访问令牌遭到滥用,请参阅 第 4.10.1 节([RFC9700])。

建议在客户端与 资源服务器之间使用端到端 TLS。如果 TLS 流量需要在中间方处终止, 请参阅 第 4.13 节([RFC9700])以获取进一步的安全建议。

1.5. 通信安全

实现必须使用一种机制来提供通信 认证、完整性和机密性,例如 传输层安全 [RFC9846], 以保护内容或标头字段中的明文凭据和令牌 在交换过程中免遭窃听,而窃听可能导致重放 (例如,参见第 2.4.1 节、第 7.5.1 节、第 3.2 节以及第 1.4.2 节)。

所有 OAuth 协议 URL(AS、RS 和客户端暴露的 URL)都必须使用 https 方案, 但环回接口重定向 URI 除外, 后者可以使用 http 方案。 使用 https 时,必须根据 第 4.3.4 节([RFC9110]) 检查 TLS 证书。 在撰写本文时, TLS 1.3 版 [RFC9846] 是最新 版本。

实现还可以支持满足其安全要求的其他 传输层安全机制。

TLS 版本和算法的确定 超出本规范的范围。 有关传输层安全的最新建议,请参阅 [BCP195], 有关证书验证和其他安全注意事项,请参阅相关 规范。

1.6. HTTP 重定向

本规范广泛使用 HTTP 重定向,其中 客户端或授权服务器会将资源所有者的 用户代理引导到另一个目的地。尽管本 规范中的示例展示了 HTTP 302 状态码的使用,但除 HTTP 307 之外,任何其他可通过用户代理完成此重定向的 方法都是允许的,并被视为 实现细节。有关详细信息,请参阅第 7.5.4 节。

1.7. 互操作性

OAuth 2.1 提供了一个具有明确定义 安全属性的丰富授权框架。

本规范将一些必需组件保留为部分定义或完全 未定义(例如客户端注册、授权服务器能力、 端点发现)。其中一些行为在可选 扩展中进行了定义,实现可以选择使用这些扩展,例如:

  • [RFC8414]: 授权服务器元数据,定义一个端点,客户端可以使用该端点查找 与特定 OAuth 服务器交互所需的信息

  • [RFC7591]: 动态客户端注册,提供一种以编程方式向 授权服务器注册客户端的机制

  • [RFC7592]: 动态客户端管理,提供一种更新动态注册的 客户端信息的机制

  • [RFC7662]: 令牌内省,定义一种资源服务器获取 访问令牌相关信息的机制

有关本次发布时 当前已知扩展的列表,请参阅附录 D。

1.7.1. 值的大小

本规范未定义 client_id、授权码、访问令牌、刷新令牌或 大多数其他协议参数的最大长度,因为这些值的长度取决于 颁发它们的一方所做的实现选择。在 实践中,实现会施加自己的限制,而超过 接收方实现限制的值将导致请求 失败。

实现不得假定其接收到的值适合 某个特定长度。颁发值的一方应该记录 其长度,并且应该考虑到将承载该值的组件的 限制。特别是,在重定向中返回的值, 例如授权码,会承载在 URI 查询字符串中,并且 HTTP 实现通常会限制请求行以及 单个标头字段的长度(第 3 节 ([RFC9112])和 第 5.4 节([RFC9110]))。 实现应该支持足够长的参数 值,以使请求保持在 第 3 节 ([RFC9112])建议的 8000 个八位字节的 请求行长度以内。资源 服务器尤其不应该对访问令牌的长度施加过小限制, 因为结构化格式的令牌(例如 [RFC9068] 中定义的令牌)通常会超过一 千字节。

1.8. 与 OAuth 2.0 的兼容性

OAuth 2.1 与 OAuth 2.0 兼容,同时应用了已知最佳当前实践中的扩展和限制。 具体而言,OAuth 2.0 核心中未规定的功能 (例如 PKCE)在 OAuth 2.1 中是必需的。此外, OAuth 2.0 中可用的某些功能,例如隐式许可或资源所有者凭据 许可类型,在 OAuth 2.1 中没有规定。此外,OAuth 2.0 中允许的某些行为 在 OAuth 2.1 中受到限制,例如 OAuth 2.1 要求 对重定向 URI 进行严格字符串匹配。

有关与 OAuth 2.0 差异的更多详细信息,请参阅第 10 节。

1.9. 符号约定

本文档中的关键词“MUST(必须)”、“MUST NOT(不得)”、“REQUIRED(必需)”、“SHALL(必须)”、“SHALL NOT(不得)”、“SHOULD(应该)”、“SHOULD NOT(不应该)”、“RECOMMENDED(建议)”、“NOT RECOMMENDED(不建议)”、 “MAY(可以)”和“OPTIONAL(可选)”,仅当它们像此处所示以 全大写形式出现时,才应按照 BCP 14 [RFC2119] [RFC8174] 中的说明进行解释。

本规范使用 [RFC5234] 的 扩充巴科斯-瑙尔形式(ABNF)表示法。此外,还从 “统一资源标识符(URI):通用语法” [RFC3986] 中引入了规则 URI-reference。

某些与安全相关的术语应按照 [RFC4949] 中定义的含义理解。这些术语包括但不限于: “攻击”、“认证”、“授权”、“证书”、 “机密性”、“凭据”、“加密”、“身份”、“签署”、 “签名”、“信任”、“验证”和“核验”。

术语“内容”应按照 第 6.4 节( [RFC9110])中的说明进行解释。

术语“用户代理”应按照 第 3.5 节( [RFC9110])中的说明进行解释。

除非另有说明,否则所有协议参数名称和值 都区分大小写。

2. 客户端注册

在启动协议之前,客户端必须已在 授权服务器处建立一个标识符(第 2.2 节)。客户端标识符在 授权服务器处建立的方式超出本 规范的范围,但通常包括客户端开发者在授权服务器的网站上手动注册 客户端(创建账户并同意 服务条款之后),或者使用动态客户端注册 [RFC7591]。 扩展还可以定义其他以编程方式建立客户端注册的方法。

客户端注册不要求客户端与 授权服务器之间进行直接交互。如果 授权服务器支持,则注册可以依赖其他方式来 建立信任并获取所需的客户端属性 (例如重定向 URI、客户端类型)。例如,注册可以 使用自签发或第三方签发的断言来完成, 或由授权服务器通过受信任 通道执行客户端发现来完成。

客户端注册必须包括:

动态客户端注册 [RFC7591] 定义了一个通用的数据模型, 即使使用手动客户端注册也可以使用该模型。

2.1. 客户端类型

OAuth 2.1 根据客户端与授权服务器进行安全认证的能力 定义了两种客户端类型。

“机密”:

拥有 AS 凭据的客户端被指定为 “机密客户端”

“公共”:

没有凭据的客户端称为“公共客户端”

任何拥有凭据的客户端都必须采取预防措施,防止其凭据 泄露和被滥用。

客户端认证使授权服务器能够确保其在 OAuth 流程中 与某个特定客户端 (由其 client_id 标识)进行交互。授权服务器可能会根据其确信自己确实在与 合法客户端通信的程度,对诸如是否每次授权都提示用户同意, 还是仅第一次提示等事项做出 策略决定。

授权服务器是否以及如何验证客户端或 提供/运营该客户端的一方的身份,超出本规范的范围。 授权服务器在决定是否允许客户端访问更敏感的资源和操作 (例如客户端凭据许可类型),以及多久提示一次用户同意时, 应该考虑对客户端身份的可信程度。

授权服务器没有支持某种特定 客户端类型的要求。

单个 client_id 不应该被视为一种以上类型的 客户端。

本规范围绕以下客户端配置文件进行设计:

“Web 应用程序”:

Web 应用程序是在 Web 服务器上运行的客户端。资源所有者通过其所使用设备上的用户代理中 渲染的 HTML 用户 界面访问客户端。客户端凭据以及颁发给客户端的任何访问 令牌均存储在 Web 服务器上,并且 不会暴露给资源所有者,也无法由资源所有者访问。

“基于浏览器的应用程序”:

基于浏览器的应用程序是一种客户端,其中 客户端代码从 Web 服务器下载,并在 资源所有者所使用设备上的用户代理(例如 Web 浏览器)中执行。 资源所有者很容易访问(并且 通常可以看到)协议数据和凭据。如果此类应用程序希望使用 客户端凭据,建议采用 前端后端模式。由于此类应用程序 驻留在用户代理内,因此它们在请求授权时可以无缝使用 用户代理的能力。

“原生应用程序”:

原生应用程序是安装并执行在 资源所有者所使用设备上的客户端。协议数据和 凭据可由资源所有者访问。假定 应用程序中包含的任何客户端认证凭据 都可以被提取。动态 颁发的访问令牌和刷新令牌可以 获得可接受级别的保护。在某些平台上,这些凭据 可免受同一 设备上其他应用程序的访问。如果此类应用程序希望使用 客户端凭据,建议采用 前端后端模式,或者在运行时 使用动态客户端注册 [RFC7591] 颁发凭据。

2.2. 客户端标识符

在授权服务器的上下文中,每个客户端都由 客户端标识符来标识——它是表示客户端所提供注册 信息的唯一字符串。虽然授权服务器通常 自行颁发客户端标识符,但它也可以为客户端标识符 由授权服务器之外的一方创建的客户端提供服务。客户端标识符不是 秘密;它会暴露给资源所有者,并且不得单独用于 客户端认证。客户端标识符在 授权服务器的上下文中是唯一的。

客户端标识符是一个不透明字符串,其长度由本 规范保持未定义,如第 1.7.1 节所述。

如果授权服务器支持客户端标识符由 授权服务器之外的其他方颁发的客户端,则授权服务器应该 采取预防措施,避免客户端如第 7.4 节所述 冒充资源所有者。

2.3. 客户端重定向 端点

客户端重定向端点(也称为“重定向端点”) 是授权服务器在完成与资源所有者的交互后, 将用户代理重定向回客户端时所使用的客户端 URI。

授权服务器会将用户代理重定向到 在客户端注册过程中预先与 授权服务器建立的客户端重定向端点之一。

重定向 URI 必须是 第 4.3 节( [RFC3986])定义的绝对 URI。重定向 URI 可以包含 查询字符串组成部分(附录 C.1),并且在添加 其他查询参数时必须保留该组成部分。重定向 URI 不得包含 片段组成部分。

2.3.1. 注册 要求

授权服务器必须要求客户端注册其完整的 重定向 URI(包括路径组成部分)。授权服务器 必须拒绝指定了与已注册 URI 不 完全匹配的重定向 URI 的授权请求,但 环回重定向除外;对于环回重定向,除 端口 URI 组成部分之外,其余部分都要求完全匹配,详见第 4.1.1 节。

授权服务器可以允许客户端注册多个 重定向 URI。

注册可以在带外进行,例如在授权服务器处手动配置 客户端信息, 也可以在运行时进行,例如推送授权请求 [RFC9126] 中的初始 POST。

对于基于私有使用 URI 方案的重定向 URI,授权 服务器应该实施第 8.4.3 节中的要求,即客户端使用 基于反向域名的方案。至少,任何 不包含句点字符(.)的私有使用 URI 方案 都应该被拒绝。

除了抗冲突属性之外, 当两个应用声称使用同一私有使用 URI 方案 (其中一个应用具有恶意行为)发生争议时,这还有助于证明所有权。 例如,如果两个应用都声称使用 com.example.app, example.com 的所有者可以请求应用商店运营方 移除仿冒应用。如果使用的是 通用 URI 方案,则此类请求更难得到证明。

客户端不得暴露可将用户浏览器转发到 从查询参数获取的任意 URI 的 URL(“开放重定向器”),如 第 7.13 节所述。 开放重定向器可能导致 授权码和访问令牌被外泄。

如果需要,客户端可以使用 state 请求参数 实现每请求 自定义,而不是在每个请求中改变重定向 URI。

如果不要求注册重定向 URI,攻击者可以 将授权端点用作开放重定向器,如 第 7.13 节所述。

2.3.2. 多个重定向 URI

如果为客户端注册了多个重定向 URI,则 客户端必须在授权请求中使用 redirect_uri 请求参数包含一个重定向 URI(第 4.1.1 节)。 如果仅为客户端注册了一个重定向 URI, 则 redirect_uri 请求参数是可选的。

2.3.3. 防止 CSRF 攻击

客户端必须防止跨站请求伪造(CSRF)攻击。在此 上下文中,CSRF 指的是发送到重定向端点、但并非 源自授权服务器,而是源自恶意第三方的请求 (详见 第 4.4.1.8 节([RFC6819]))。已经 确保授权服务器支持 code_challenge 参数的客户端可以 依赖该机制提供的 CSRF 保护。在 OpenID Connect 流程中, 验证 nonce 参数可提供 CSRF 保护。否则, 必须使用通过 state 参数携带并安全 绑定到用户代理的一次性 CSRF 令牌来提供 CSRF 保护(参见 第 7.10 节)。

2.3.4. 防止 混淆攻击

当 OAuth 客户端只能与一个授权 服务器交互时,不需要混淆防御。但是,在 OAuth 客户端与 两个或更多授权服务器交互的场景中,客户端必须防止混淆攻击。 为了防止混淆攻击,客户端只能处理与其发送相应请求的 发行者相对应的重定向响应,并且必须来自发起该 授权请求的同一个用户代理。

有关两种不同混淆攻击防御方式的详细说明,请参阅第 7.15 节。

2.3.5. 无效端点

如果授权请求由于缺少、 无效或不匹配的重定向 URI 而验证失败,授权服务器 应该告知资源所有者该错误,并且不得 自动将用户代理重定向到无效的重定向 URI。

2.3.6. 端点内容

发送到客户端端点的重定向请求通常会产生 一个由用户代理处理的 HTML 文档响应。如果 HTML 响应直接作为重定向请求的结果提供, HTML 文档中包含的任何脚本都将在可完全 访问重定向 URI 及其中所含工件(例如授权码)的情况下执行。 此外,包含授权码的请求 URL 可能会在 HTTP Referer 标头中发送给页面中加载的任何嵌入图像、样式表 和其他元素。

客户端不应该在重定向 URI 端点响应中包含任何第三方脚本(例如第三方 分析、社交插件、广告网络)。相反,它应该从 URI 中提取工件,并再次将用户代理重定向到另一个端点, 且不暴露这些工件(无论是在 URI 中还是其他位置)。如果包含第三方 脚本,客户端必须确保其自己的脚本 (用于从 URI 中提取并移除凭据) 首先执行。

2.4. 客户端认证

只有在底层凭据的 颁发/注册和分发过程能够确保其机密性的情况下, 授权服务器才必须依赖客户端认证。

对于机密客户端,授权服务器可以接受任何 满足其安全要求的客户端认证形式 (例如客户端密钥、公钥/私钥对)。

建议对客户端认证使用非对称(基于公钥的)方法, 例如 mTLS [RFC8705],或根据 [RFC7521]、[RFC7523] 及其更新 [I-D.ietf-oauth-rfc7523bis] 使用已签名的 JWT (“私钥 JWT”) (在 [OpenID.Connect] 中定义为 客户端认证方法 private_key_jwt)。 使用此类客户端认证方法时,授权 服务器无需存储敏感的对称密钥,这使这些 方法能够更稳健地抵御多种攻击,并使客户端 能够管理自己的密钥和密钥轮换。

使用基于 JWT 的客户端认证时,客户端和授权服务器 必须遵循 [I-D.ietf-oauth-rfc7523bis] 中有关 aud 值的更新指南。

当无法进行客户端认证时,授权服务器 应该使用其他方式验证客户端身份——例如, 要求注册客户端重定向 URI 或请求资源所有者确认身份。在请求资源所有者授权时, 有效的重定向 URI 本身不足以验证客户端身份, 但可以用来防止在获得资源所有者授权后 将凭据交付给仿冒客户端。

客户端在每个请求中不得使用一种以上的认证方法, 以避免出现哪个认证机制 对该请求具有权威性的冲突。

授权服务器必须考虑 与未经认证的客户端交互所带来的安全影响,并采取措施限制 向此类客户端颁发的令牌可能暴露的风险 (例如限制刷新令牌的生命周期)。

授权服务器与某个 客户端身份相关联的权限,必须取决于对客户端识别和 客户端凭据生命周期管理整体过程的评估。 有关更多详细信息,请参阅第 7.2 节。

2.4.1. 客户端密钥

为了支持拥有客户端密钥的机密客户端, 授权服务器必须支持客户端使用以下 参数在请求正文内容中包含客户端凭据:

"client_id":

必需。在 第 2.2 节所述注册过程中颁发给客户端的客户端标识符。

"client_secret":

必需。客户端密钥。

这些参数只能在请求内容中传输, 不得包含在请求 URI 中。

这也称为 client_secret_post,如 第 2 节([RFC7591])中所定义。

例如,使用内容参数刷新访问令牌(第 4.3 节)的请求 如下(仅为显示目的添加额外换行):

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

grant_type=refresh_token&refresh_token=tGzv3JOkF0XG5Qx2TlKWIA
&client_id=s6BhdRkqt3&client_secret=7Fjfp0ZBr1KtDRbnfVdmIw

授权服务器可以支持 HTTP Basic 认证方案,以认证已向其颁发 客户端密钥的客户端。

当使用 第 11 节([RFC9110]) 定义的 HTTP Basic 认证方案 向授权服务器进行认证时,客户端标识符按照 附录 B使用 application/x-www-form-urlencoded 编码算法进行编码, 并将编码后的值用作用户名;客户端 密钥使用相同算法编码,并用作 密码。

这也称为 client_secret_basic,如 第 2 节([RFC7591])中所定义。

例如(仅为显示目的添加额外换行):

Authorization: Basic czZCaGRSa3F0Mzo3RmpmcDBaQnIxS3REUmJuZlZkbUl3

注意:这种先对客户端标识符和密钥进行表单编码, 然后将编码后的值用作 HTTP Basic 认证用户名 和密码的方法,过去曾导致许多互操作性问题。一些 实现遗漏了编码步骤,或决定仅编码 某些字符,或在验证 凭据时忽略了编码要求,导致客户端不得不针对 不同授权服务器以特殊方式提交 凭据。将凭据包含在请求正文内容中可以避免编码问题,并实现 更具互操作性的实现。

由于客户端密钥认证方法涉及密码, 授权服务器必须保护任何使用该方法的端点免受 暴力破解攻击。

2.4.2. 其他 认证方法

授权服务器可以支持任何符合其安全要求的适当认证 方案。使用其他 认证方法时,授权服务器必须定义 客户端标识符(注册记录)与 认证方案之间的映射。

一些其他认证方法,例如 mTLS [RFC8705] 和私钥 JWT([RFC7523]、 [I-D.ietf-oauth-rfc7523bis]) 定义在 “OAuth 令牌端点认证方法”注册表中, 并且可以用作通用客户端认证方法,而不仅限于 保护令牌端点这一特定用途。

2.5. 未注册客户端

本规范不要求客户端必须在 授权服务器处注册。 但是,使用未注册客户端超出本 规范的范围,并且需要额外的安全分析以及对其 互操作性影响的审查。

3. 协议端点

授权过程使用两个授权服务器端点 (HTTP 资源):

以及一个客户端端点:

并非每种授权许可类型都会使用这两个端点。 扩展许可类型可以按需要定义其他端点。

3.1. 授权端点

授权端点用于与资源 所有者交互并获取授权许可。授权服务器 必须首先认证资源所有者。授权服务器 认证资源所有者的方式 (例如用户名和密码登录、通行密钥、联合登录或使用已建立的 会话) 超出本规范的范围。

客户端获取 授权端点 URL 的方式超出本规范的范围, 但该 URL 通常在服务文档 或授权服务器的元数据文档 [RFC8414] 中提供。

授权端点 URL 不得包含片段组成部分, 并且可以包含查询字符串组成部分(附录 C.1), 在添加其他查询参数时必须保留该组成部分。

授权服务器必须支持在授权端点使用 HTTP GET 方法(第 9.3.1 节([RFC9110])),并且还可以支持 POST 方法(第 9.3.3 节([RFC9110]))。

授权服务器必须忽略发送到 授权端点的无法识别的请求参数。

本规范定义的请求和响应参数 不得出现多次。 这一要求也适用于扩展定义的参数, 除非扩展明确为某个特定 参数另作规定。 未带值发送的参数必须被视为 已从请求中省略。

授权服务器在重定向可能包含 用户凭据的请求时,必须避免意外转发这些用户凭据 (详见第 7.5.4 节)。

授权端点不得支持跨源资源共享 [WHATWG.CORS], 因为客户端不会直接访问该 端点,而是将用户代理重定向到该端点。

许可类型定义授权端点所需的参数。 本规范定义了“授权码许可”(第 4.1 节), 包括请求中要包含的基础参数列表。诸如 推送授权请求([RFC9126])之类的扩展定义了用于向 授权端点发送请求的不同参数集。

3.2. 令牌端点

客户端使用令牌端点,通过 第 4 节和 第 4.3 节中所述之类的许可 获取访问令牌。

客户端获取令牌 端点 URL 的方式超出本规范的范围,但该 URL 通常在服务文档中提供,并在 客户端开发期间进行配置,或者由授权服务器的元数据 文档 [RFC8414] 提供,并在 运行时以编程方式获取。

令牌端点 URL 不得包含片段组成部分, 并且可以包含查询字符串组成部分(附录 C.1)。

客户端向令牌端点发出请求时必须使用 HTTP POST 方法。

授权服务器必须忽略发送到 令牌端点的无法识别的请求参数。

未带值发送的参数必须被视为 已从请求中省略。本规范定义的请求和响应参数 不得出现多次。 这一要求也适用于扩展定义的参数, 除非扩展明确为某个特定 参数另作规定。

希望支持基于浏览器的应用程序的授权服务器 (例如,仅在客户端 JavaScript 中运行且 无法访问支持性后端服务器的应用程序)需要确保令牌端点 支持必要的 CORS [WHATWG.CORS] 标头,以允许应用程序看到 响应。 如果授权服务器向应用程序提供其他端点,例如 元数据 URL、动态客户端注册、撤销、内省、发现或 用户信息端点,则基于浏览器的 应用程序也可能访问这些端点,并且这些端点也需要定义允许访问的 CORS 标头。 有关更多详细信息,请参阅 [I-D.ietf-oauth-browser-based-apps]。

3.2.1. 客户端 认证

机密客户端向令牌端点发出 请求时,必须按照 第 2.4 节所述向授权服务器 进行认证。

客户端认证用于:

  • 强制将刷新令牌和 授权码绑定到它们所颁发给的 客户端。当授权码通过不安全通道传输到 重定向端点时,客户端认证增加了一层额外的安全保护。

  • 通过禁用客户端或 更改其凭据,从客户端被攻破的情况中恢复,从而防止攻击者滥用 被盗的刷新令牌。更改单组客户端 凭据比撤销整组 刷新令牌快得多。

  • 实施认证管理最佳实践, 这些实践要求定期轮换凭据。轮换整组 刷新令牌可能很困难,而轮换单组 客户端凭据则容易得多。

3.2.2. 令牌端点 请求

客户端通过使用 附录 C.2规定的表单编码序列化 格式,并在 HTTP 请求内容中采用 UTF-8 字符编码发送以下参数,来向令牌端点发出请求:

"grant_type":

必需。客户端在特定令牌请求中使用的 许可类型标识符。 本规范定义了值 authorization_code、 refresh_token 和 client_credentials。 许可类型决定令牌请求需要或支持的 其他参数。这些许可类型的 详细信息在下文定义。

"client_id":

可选。当使用依赖该参数的 客户端认证形式,或者 grant_type 要求 识别公共客户端时,需要客户端标识符。

机密客户端必须按照第 3.2.1 节所述向授权 服务器进行认证。

例如,客户端发出以下 HTTPS 请求 (仅为显示目的添加额外换行):

POST /token HTTP/1.1
Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code
&code=SplxlOBeZQQYbYS6WxSbIA
&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb
&code_verifier=3641a2d12d66101249cdf7a79c000c1f8c05d2aafcf14bf146497bed

授权服务器必须:

  • 要求机密客户端 (或具有其他认证要求的客户端)进行客户端认证,

  • 如果包含客户端认证,则 认证客户端

还适用其他特定于许可类型的处理规则,这些规则在相应的 许可类型中规定。

3.2.3. 令牌端点 响应

如果访问令牌请求有效且已获授权, 授权服务器将颁发访问令牌以及可选的刷新 令牌。

如果客户端认证失败或无效,授权 服务器将返回第 3.2.4 节中所述的错误响应。

授权服务器按照附录 C.3创建 HTTP 响应, 使用 [RFC8259]定义的 application/json 媒体类型, 并包含以下参数及 HTTP 200(OK)状态码, 以颁发访问令牌以及可选的刷新令牌:

"access_token":

必需。授权 服务器颁发的访问令牌。

"token_type":

必需。按照 第 1.4 节所述颁发的访问令牌类型。该值 不区分大小写。

"expires_in":

建议。一个表示访问令牌生命周期(以秒为单位)的 JSON 数字。例如,值 3600 表示访问令牌将在 响应生成后的一小时过期。 如果省略,授权服务器应该通过其他方式提供该 生命周期,或者记录默认值。请注意, 授权服务器可能会提前使访问 令牌过期,因此客户端不得期望访问令牌在所提供的 生命周期内始终有效。

"scope":

如果与客户端请求的作用域相同,则建议包含; 否则为必需。访问令牌的作用域,如 第 1.4.1 节所述。

"refresh_token":

可选。刷新令牌,可用于 根据相应令牌请求中传递的许可 获取新的访问令牌。

授权服务器应该根据风险评估 以及其自身策略,决定是否向某个客户端颁发刷新令牌。如果 授权服务器决定不颁发刷新令牌,客户端 可以通过重新开始 OAuth 流程来获取新的访问令牌,例如 发起新的授权码请求。在这种情况下,授权 服务器可以利用 Cookie 和持久许可来优化用户 体验。

如果颁发刷新令牌,这些刷新令牌必须绑定到 资源所有者同意的作用域和资源服务器。 这是为了防止合法客户端提升权限,并 降低刷新令牌泄露的影响。

这些参数按照附录 C.3中的说明序列化为 JavaScript Object Notation (JSON) 结构。

授权服务器在任何 包含令牌、凭据或其他敏感 信息的响应中,都必须包含 HTTP Cache-Control 响应标头字段(参见 第 5.2 节([RFC9111])),其值为 no-store。

例如:

HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-store

{
  "access_token": "2YotnFZFEjr1zCsicMWpAA",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "tGzv3JOkF0XG5Qx2TlKWIA",
  "example_parameter": "example_value"
}

客户端必须忽略响应中无法识别的值名称。 从授权服务器接收到的令牌及其他值的长度 保持未定义,如第 1.7.1 节所述。

3.2.4. 令牌端点 错误响应

授权服务器使用 HTTP 400(错误请求) 状态码进行响应(除非另有规定),并在响应中包含以下 参数:

"error":

必需。以下错误代码之一的单个 ASCII [USASCII] 值:

"invalid_request":

请求缺少必需参数、 包含不支持的参数值(许可类型除外)、 重复某个参数、包含多个凭据、 使用一种以上机制来认证 客户端、虽然授权请求中未发送 code_challenge 却包含 code_verifier, 或者以其他方式格式错误。

"invalid_client":

客户端认证失败(例如未知 客户端、未包含客户端认证或不支持的 认证方法)。授权服务器可以 返回 HTTP 401(未授权)状态码,以指明 支持哪些 HTTP 认证方案。如果 客户端尝试通过 Authorization 请求标头字段进行认证,则授权服务器必须 使用 HTTP 401(未授权)状态码进行响应,并 包含与客户端所使用认证方案相匹配的 WWW-Authenticate 响应标头字段。

"invalid_grant":

所提供的授权许可(例如 授权码、资源所有者凭据)或刷新令牌 无效、已过期、已撤销、与授权请求中使用的 重定向 URI 不匹配,或颁发给了 另一个客户端。

"unauthorized_client":

已认证的客户端无权 使用此授权许可类型。

"unsupported_grant_type":

授权服务器不支持该 授权许可类型。

"invalid_scope":

请求的作用域无效、未知、 格式错误,或 超出了资源所有者授予的作用域。

error 参数的值不得 包含集合 %x20-21 / %x23-5B / %x5D-7E 之外的字符。

"error_description":

可选。人类可读的 ASCII [USASCII] 文本,用于提供 附加信息,以帮助客户端开发者 理解所发生的错误。 error_description 参数的值不得包含 集合 %x20-21 / %x23-5B / %x5D-7E 之外的字符。

"error_uri":

可选。一个标识人类可读网页的 URI, 该网页包含有关错误的信息,用于向客户端 开发者提供有关错误的附加信息。 error_uri 参数的值必须符合 URI-reference 语法,因此不得包含 集合 %x21 / %x23-5B / %x5D-7E 之外的字符。

这些参数使用附录 C.3中定义的 application/json 媒体类型包含在 HTTP 响应内容中。

例如:

HTTP/1.1 400 Bad Request
Content-Type: application/json
Cache-Control: no-store

{
 "error": "invalid_request"
}

4. 许可类型

为了请求访问令牌,客户端从 资源所有者获取授权。本规范定义了以下授权许可类型:

它还提供了一种用于定义其他许可类型的扩展机制。

4.1. 授权码 许可

授权码许可类型用于获取访问 令牌和刷新令牌。

此许可类型使用额外的授权端点,使 授权服务器 能够与资源所有者交互,以获得访问资源的同意。

由于这是一个基于重定向的流程,客户端必须能够 通过资源所有者的用户代理(通常是 Web 浏览器)发起该流程,并且能够接收来自授权服务器的重定向。

 +----------+
 |   资源   |
 |  所有者  |
 +----------+
       ^
       |
       |
 +-----|----+          客户端标识符          +---------------+
 | .---+---------(1)-- & 重定向 URI -------->|               |
 | |   |    |                                 |               |
 | |   '---------(2)-- 用户进行认证 --------->|               |
 | | 用户-  |                                 |     授权      |
 | | 代理   |                                 |     服务器     |
 | |        |                                 |               |
 | |    .--------(3)------ 授权码 -----------<|               |
 +-|----|---+                                 +---------------+
   |    |                                         ^      v
   |    |                                         |      |
   ^    v                                         |      |
 +---------+                                      |      |
 |         |>---(4)------ 授权码 ----------------'      |
 |  客户端  |          & 重定向 URI                     |
 |         |                                             |
 |         |<---(5)------ 访问令牌 ---------------------'
 +---------+        (附可选刷新令牌)
图 3: 授权码流程

图 3所示的流程包括以下步骤:

(1) 客户端通过将资源所有者的 用户代理引导至授权端点来发起流程。客户端包含 其客户端标识符、代码质询(从生成的代码验证器派生)、 可选的请求作用域、可选的本地状态,以及一个 重定向 URI,授权服务器将在访问获准(或被拒绝)后通过该 URI 将 用户代理送回。

(2) 授权服务器(通过 用户代理)认证资源所有者,并确定资源所有者 是授予还是拒绝客户端的访问请求。

(3) 假设资源所有者授予访问权限,授权 服务器使用先前提供的 重定向 URI(在请求中或客户端注册期间提供) 将用户代理重定向回客户端。重定向 URI 包含一个 授权码以及客户端先前提供的任何本地状态。

(4) 客户端通过包含上一步中收到的授权码 以及其代码验证器,向授权 服务器的令牌端点请求访问令牌。 发出请求时,如果可以, 客户端会向授权服务器进行认证。客户端 包含用于获取授权 码的重定向 URI 以供验证。

(5) 授权服务器在可能的情况下认证客户端, 验证 授权码、验证代码验证器,并确保收到的重定向 URI 与步骤 (3) 中用于将用户代理重定向到客户端的 URI 相匹配。 如果有效,授权服务器将以 访问令牌以及可选的刷新令牌进行响应。

4.1.1. 授权 请求

为了开始授权请求,客户端通过向授权服务器的 授权端点 URI 添加参数来构建 授权请求 URI。客户端最终会将用户代理重定向 到此 URI 以发起请求。

客户端为每个 授权请求使用一个称为“代码验证器”的唯一秘密,以防止授权码 注入和 CSRF 攻击。客户端首先生成代码验证器,然后派生 要包含在授权请求中的“代码质询”。客户端 在令牌端点交换授权码时使用代码验证器,以 证明使用该 授权码的客户端就是请求该授权码的同一个客户端。

客户端按照附录 C.1所述,通过向授权端点 URI 的查询组成部分添加以下 参数来构造请求 URI:

"response_type":

必需。授权端点支持不同的 请求和响应参数集合。客户端通过使用特定的 response_type 值来确定流程类型。本规范定义了值 code,必须使用该值来表示 客户端希望使用授权码流程。

扩展响应类型可以包含以空格分隔(%x20)的 值列表,其中值的顺序无关紧要(例如,响应 类型 a b 与 b a 相同)。此类复合 响应类型的含义由相应规范定义。

一些扩展响应类型由 [OpenID.Connect] 定义。

如果授权请求缺少 response_type 参数, 或者无法理解该响应类型,授权服务器 必须返回第 4.1.2.1 节所述的错误响应。

"client_id":

必需。第 2.2 节所述的客户端标识符。

"code_challenge":

必需,除非满足第 7.5.1 节中的特定要求。 从代码验证器派生的代码质询。

"code_challenge_method":

必需,值为 S256 或未来扩展定义的值

"redirect_uri":

如果仅为此客户端注册了一个重定向 URI,则为可选。 如果为此客户端注册了多个重定向 URI,则为必需。 参见第 2.3.2 节。

"scope":

可选。访问请求的作用域,如 第 1.4.1 节所述。

"state":

可选。客户端用于在请求和回调之间 保持 状态的不透明值。授权 服务器在将用户代理重定向回 客户端时包含此值。该值被携带在 授权请求 URI 的查询组成部分中,并在重定向回 客户端时再次携带,因此其长度实际上受授权服务器、 用户代理和客户端所接受的 URI 和 HTTP 标头字段长度限制;参见第 1.7.1 节。

code_verifier 是为 每个授权请求生成的唯一高熵 密码学随机字符串,使用非保留字符 [A-Z] / [a-z] / [0-9] / "-" / "." / "_" / "~", 最小长度为 43 个字符,最大长度为 128 个字符。

客户端临时存储 code_verifier,并 计算其在授权请求中使用的 code_challenge。

code_verifier 的 ABNF 如下。

code-verifier = 43*128unreserved
unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
ALPHA = %x41-5A / %x61-7A
DIGIT = %x30-39

客户端必须使用不会在授权请求中 暴露 code_verifier 的代码质询方法。 否则,能够读取授权请求的攻击者(参见 [RFC9700] 中的攻击者 A4)可以 破坏该机制提供的安全性。目前,S256 是唯一此类方法。

注意:代码验证器应该具有足够的熵,以使 猜测该值在实践中不可行。建议使用 合适的随机数生成器的输出来创建一个 32 个八位字节的 序列。然后对该八位字节序列进行 base64url 编码,以生成一个 43 个八位字节的 URL 安全字符串,用作代码验证器。

然后,客户端通过使用有效的转换方法转换代码验证器, 创建从代码 验证器派生的 code_challenge:

S256
  code_challenge = BASE64URL-ENCODE(SHA256(ASCII(code_verifier)))

本规范仅定义 S256 转换。未来扩展 可以定义其他转换方法。

code_challenge 的 ABNF 如下。

code-challenge = 43*128unreserved
unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
ALPHA = %x41-5A / %x61-7A
DIGIT = %x30-39

code_challenge 和 code_verifier 属性采用自被称为“代码交换证明密钥” (Proof-Key for Code Exchange,PKCE)的 OAuth 2.0 扩展 [RFC7636],该技术最初在其中 开发。本规范移除了 [RFC7636] 中定义的 plain 转换方法,并明确禁止使用该方法。有关更多详细信息,请参阅第 7.5.2 节。

授权服务器必须支持 code_challenge 和 code_verifier 参数。

客户端必须使用 code_challenge 和 code_verifier,并且 授权服务器必须强制使用它们,除非符合 第 7.5.1 节所述的条件。即使在这种情况下,仍然建议按上述方式使用并强制执行 code_challenge 和 code_verifier。

state 和 scope 参数不应该 以明文形式包含敏感的 客户端或资源所有者信息,因为它们可能通过 不安全的通道传输或以不安全的方式存储。

客户端使用 HTTP 重定向,或通过用户代理可用的其他方式,将资源所有者引导至构造的 URI。

例如,客户端引导用户代理发出以下 HTTPS 请求(仅为显示目的添加额外换行):

GET /authorize?response_type=code&client_id=s6BhdRkqt3&state=xyz
    &redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb
    &code_challenge=6fdkQaPm51l13DSukcAH3Mdx7_ntecHYd1vi3n0hMZY
    &code_challenge_method=S256 HTTP/1.1
Host: server.example.com

授权服务器验证请求,以确保所有 必需参数均存在且有效。

特别是,如果请求中存在 redirect_uri,授权服务器必须对其进行验证, 确保它与客户端注册期间先前建立的已注册 重定向 URI 之一相匹配(第 2 节)。 比较两个 URI 时,授权服务器必须确保 两个 URI 相等,详见 第 6.2.1 节([RFC3986])中的简单字符串比较。 唯一例外是使用 localhost URI 的原生应用:在这种情况下,授权 服务器 必须允许可变端口号,如第 8.4.2 节所述。

如果请求有效, 授权服务器会认证资源所有者,并获得 授权决定(通过询问资源所有者或 通过其他方式确定批准)。

确定决定后,授权服务器使用 HTTP 重定向响应,或通过 用户代理可用的其他方式,将 用户代理引导至所提供的客户端重定向 URI。

4.1.2. 授权 响应

如果资源所有者授予访问请求,授权 服务器会颁发授权码,并通过 使用附录 C.1所述的查询字符串序列化, 将以下参数添加到 重定向 URI 的查询组成部分中来将其交付给客户端, 除非扩展另有规定:

"code":

必需。授权码由 授权服务器生成,并且对客户端是不透明的。授权码必须在 颁发后很快过期,以降低泄露风险。建议 授权码的最大生命周期为 10 分钟。 授权码绑定到 客户端标识符、代码质询和重定向 URI。

"state":

如果客户端授权请求中存在 state 参数, 则为必需。其值必须与从 客户端收到的值完全相同。

"iss":

必需。授权 服务器的发行者标识符,如果客户端与 多个授权服务器交互,客户端可以使用它来防止混淆攻击。有关客户端如何使用它防止混淆攻击的 更多详细信息,请参阅第 7.15 节和 [RFC9207]。

例如,授权服务器通过 发送以下 HTTP 响应来重定向用户代理:

HTTP/1.1 302 Found
Location: https://client.example.com/cb?code=SplxlOBeZQQYbYS6WxSbIA
          &state=xyz&iss=https%3A%2F%2Fauthorization-server.example.com

客户端必须忽略无法识别的响应参数。 授权码字符串的长度由本 规范保持未定义,如第 1.7.1 节所述。

授权服务器必须将 code_challenge 和 code_challenge_method 值与所颁发的授权码相关联, 以便稍后验证代码质询。

服务器用于将 code_challenge 与所颁发代码相关联的确切方法超出本规范的范围。 代码质询可以存储在服务器上,并在那里与 代码相关联。code_challenge 和 code_challenge_method 值可以 以加密形式存储在代码本身中,但服务器 不得在响应参数中以 AS 以外的实体 能够提取的形式包含 code_challenge 值。

客户端必须防止攻击者将授权码注入(重放)到 授权响应中。使用 code_challenge 和 code_verifier 可以防止授权码注入,因为 授权服务器会拒绝 code_verifier 不匹配的令牌请求。 有关更多详细信息,请参阅第 7.5.1 节。

4.1.2.1. 授权错误响应

如果请求因缺少、无效或 不匹配的 重定向 URI 而失败,或者客户端标识符缺失或无效, 授权服务器不得将用户代理重定向到 无效的重定向 URI,并且应该告知资源所有者该 错误,例如在用户浏览器中向用户显示消息。 直接向用户代理返回错误响应时, 授权服务器应该使用 HTTP 400(错误请求)状态码。 用于令牌端点客户端认证 错误的 HTTP 401(未授权)状态码不适用于授权端点 请求错误。

授权服务器在将错误响应重定向到客户端之前,必须验证客户端 标识符和重定向 URI。两者都经过验证后,授权服务器使用下方定义的错误 代码重定向请求错误。

授权服务器必须拒绝来自公共客户端且不包含 code_challenge 的请求, 并且必须拒绝来自其他客户端的此类请求,除非有 合理把握确认客户端通过其他方式缓解了授权码注入。 详见第 7.5.1 节。

如果服务器不支持所请求的 code_challenge_method 转换, 授权端点必须返回 授权错误响应,并将 error 值设置为 invalid_request。error_description 或 error_uri 的响应应该说明错误性质,例如不支持转换 算法。

如果资源所有者拒绝访问请求,或者 在客户端标识符和重定向 URI 验证后请求失败, 授权服务器通过将用户代理重定向 到重定向 URI,并按照 附录 C.1所述向重定向 URI 的查询组成部分添加以下 参数来告知客户端:

"error":

必需。以下 错误代码之一的单个 ASCII [USASCII] 值:

"invalid_request":

请求缺少必需 参数、包含无效的 参数值、多次包含某个参数,或者存在其他格式错误。

"unauthorized_client":

客户端无权使用此方法 请求授权 码。

"access_denied":

资源所有者或 授权服务器拒绝了 请求。

"unsupported_response_type":

授权服务器不 支持使用此方法获取 授权码。

"invalid_scope":

请求的作用域无效、 未知或格式错误。

"server_error":

授权服务器遇到了意外 情况,导致其无法满足请求。 (需要此错误代码,是因为无法通过 HTTP 重定向向客户端返回 500 内部服务器 错误 HTTP 状态码。)

"temporarily_unavailable":

由于服务器暂时过载或正在维护, 授权服务器当前无法处理 该请求。(需要此错误代码,是因为无法 通过 HTTP 重定向向客户端返回 503 服务不可用 HTTP 状态码。)

error 参数的值 不得包含 集合 %x20-21 / %x23-5B / %x5D-7E 之外的字符。

"error_description":

可选。人类可读的 ASCII [USASCII] 文本, 提供 附加信息,用于帮助客户端开发者 理解发生的错误。 error_description 参数的值不得包含 集合 %x20-21 / %x23-5B / %x5D-7E 之外的字符。

"error_uri":

可选。标识一个包含 错误信息的人类可读 网页的 URI,用于向客户端 开发者提供有关错误的附加信息。 error_uri 参数的值必须符合 URI-reference 语法,因此不得包含 集合 %x21 / %x23-5B / %x5D-7E 之外的字符。

"state":

如果客户端授权请求中存在 state 参数, 则为必需。其值必须与从 客户端收到的值完全相同。

"iss":

必需。授权服务器的 发行者标识符。有关详细信息,请参阅上面的 第 4.1.2 节。

例如,授权服务器通过以下 HTTP 响应 重定向用户代理,以指明 请求已被拒绝:

HTTP/1.1 302 Found
Location: https://client.example.com/cb?error=access_denied
          &state=xyz&iss=https%3A%2F%2Fauthorization-server.example.com

4.1.3. 令牌端点 扩展

授权许可类型在令牌端点通过 grant_type 值 authorization_code 来标识。

如果设置了此值,则支持第 3.2.2 节之外的以下附加令牌请求 参数:

"code":

必需。从 授权服务器接收到的授权码。

"code_verifier":

如果授权 请求中包含 code_challenge 参数,则为必需。否则不得使用。原始代码验证器字符串。

"client_id":

如果客户端未按照第 3.2.1 节所述向 授权服务器进行认证,则为必需。

对于给定的授权码,授权服务器必须只返回一次访问令牌。

如果使用与先前成功令牌请求相同的 授权码发出了第二个有效令牌请求, 授权服务器必须拒绝该请求,并且应该 撤销(如果可能)此前基于该授权码颁发的所有访问令牌和刷新令牌。 有关更多详细信息,请参阅第 7.5.3 节。

例如,客户端发出以下 HTTPS 请求 (仅为显示目的添加额外换行):

POST /token HTTP/1.1
Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code
&code=SplxlOBeZQQYbYS6WxSbIA
&code_verifier=3641a2d12d66101249cdf7a79c000c1f8c05d2aafcf14bf146497bed

除第 3.2.2 节中的处理规则之外,授权服务器还必须:

  • 确保授权码是颁发给经过认证的 机密 客户端的,或者如果客户端是公共客户端,则确保该 代码是颁发给请求中的 client_id 的,

  • 验证授权码有效,

  • 当且仅当授权 请求中存在 code_challenge 参数时,验证 code_verifier 参数是否存在,

  • 如果存在 code_verifier,则通过根据客户端指定的 code_challenge_method 方法首先对其进行转换,然后根据收到的 code_verifier 计算 代码质询,并将其 与先前关联的 code_challenge 进行比较,从而验证 code_verifier,以及

  • 如果与令牌请求中的授权码相关联的 授权请求中没有 code_challenge, 授权服务器必须 拒绝该令牌请求。

有关令牌请求中的 redirect_uri 参数与 OAuth 2.0 客户端 向后兼容的详细信息,请参阅第 10.2 节。

4.2. 客户端凭据 许可

当客户端请求访问其 控制下的受保护资源,或者其他资源所有者此前已经 与授权服务器安排好的受保护资源(其安排方法超出 本规范的范围)时,客户端可以仅使用其客户端 凭据(或其他受支持的认证方式)请求访问令牌。

客户端凭据许可类型必须仅由机密客户端使用。

     +---------+                                  +---------------+
     |         |                                  |               |
     |         |>--(1)--- 客户端认证 ------------>|     授权      |
     |  客户端  |                                  |     服务器     |
     |         |<--(2)---- 访问令牌 -------------<|               |
     |         |                                  |               |
     +---------+                                  +---------------+
图 4: 客户端凭据许可

图 4所示的客户端凭据许可的使用包括以下步骤:

(1) 客户端向授权服务器进行认证,并 从令牌端点请求访问令牌。

(2) 授权服务器认证客户端,如果有效, 则颁发访问令牌。

4.2.1. 令牌端点 扩展

客户端凭据许可类型在令牌 端点通过 grant_type 值 client_credentials 来标识。

如果设置了此值,则支持第 3.2.2 节之外的以下附加令牌请求 参数:

"scope":

可选。访问请求的作用域,如 第 1.4.1 节所述。

例如,客户端使用 传输层安全发出以下 HTTP 请求(仅为显示目的添加额外换行):

POST /token HTTP/1.1
Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded

grant_type=client_credentials

授权服务器必须认证客户端。

4.3. 刷新令牌许可

刷新令牌是授权服务器颁发给 客户端的一种凭据,可用于 基于现有许可获取新的(新鲜的)访问令牌。客户端使用此选项 是因为先前的访问 令牌已过期,或者客户端此前获取的访问令牌的作用域比 相应许可批准的作用域更窄, 而随后需要在同一许可下获取具有不同作用域的访问令牌。

刷新令牌在传输和存储过程中必须保持机密,并且 只能在授权服务器与该刷新令牌所 颁发给的客户端之间共享。授权服务器必须维护 刷新令牌与其所 颁发给的客户端之间的绑定关系。

每当可以认证客户端身份时,授权服务器必须验证刷新 令牌与客户端身份之间的绑定关系。 当无法进行客户端认证时, 授权服务器应该颁发发送方约束的刷新令牌, 或者使用第 4.3.1 节所述的刷新令牌轮换。

授权服务器必须确保未经授权的参与方无法 生成、修改或猜测出有效的刷新令牌。

4.3.1. 令牌端点 扩展

刷新令牌许可类型在令牌端点 通过 grant_type 值 refresh_token 来标识。

如果设置了此值,则支持第 3.2.2 节之外的以下附加参数:

"refresh_token":

必需。颁发给客户端的刷新令牌。

"scope":

可选。访问请求的作用域,如 第 1.4.1 节所述。请求的作用域不得包含 最初未由资源所有者授予的任何作用域,如果省略, 则视为等于资源所有者最初授予的 作用域。

由于刷新令牌通常是用于 请求其他访问令牌的长期凭据,因此刷新令牌会绑定到 其所颁发给的客户端。机密客户端 必须按照第 3.2.1 节所述向授权服务器进行认证。

例如,客户端使用 传输层安全发出以下 HTTP 请求(仅为显示目的添加额外换行):

POST /token HTTP/1.1
Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded

grant_type=refresh_token&refresh_token=tGzv3JOkF0XG5Qx2TlKWIA

除第 3.2.2 节中的处理规则之外,授权服务器还必须:

  • 如果请求中包含客户端认证, 确保刷新令牌颁发给了经过认证的客户端,或者如果请求中包含 client_id,则确保刷新令牌颁发给了 匹配的客户端

  • 验证与此刷新 令牌相对应的许可仍处于活动状态

  • 验证刷新令牌

对于公共客户端,授权服务器必须使用以下方法之一来检测 恶意行为者对刷新令牌的重放:

  • 发送方约束的刷新令牌:授权 服务器 以密码学方式将刷新令牌绑定到某个客户端 实例,例如通过使用 DPoP [RFC9449] 或 mTLS [RFC8705]。

  • 刷新令牌轮换:授权 服务器在每次访问令牌刷新响应中颁发新的 刷新令牌。先前的刷新令牌会失效,但有关 两者关系的信息由授权服务器保留。如果 刷新令牌被泄露,并随后由攻击者和合法客户端 同时使用,其中一方将提交一个 已失效的刷新令牌,从而告知授权 服务器发生了泄露。授权服务器无法确定 哪一方提交了无效刷新令牌,但它会 撤销活动刷新令牌以及与之关联的访问授权 许可。这会阻止攻击, 代价是迫使合法客户端获取新的 授权许可。

实现说明:刷新令牌所属的许可 可以编码到刷新令牌本身中。这可以使 授权服务器高效确定刷新令牌所属的许可, 进而确定所有需要撤销的刷新令牌。 在这种情况下,授权服务器必须确保 刷新令牌值的完整性,例如 使用签名。

4.3.2. 刷新令牌 响应

如果有效且已获授权,授权服务器将按照第 3.2.3 节所述颁发访问 令牌。

授权服务器可以颁发新的刷新令牌,在这种 情况下, 客户端必须丢弃旧刷新令牌,并将其替换为 新刷新令牌。

4.3.3. 刷新令牌 建议

授权服务器在向客户端颁发新的刷新令牌后,可以撤销旧的 刷新令牌。如果 颁发了新的刷新令牌,则其作用域必须与客户端在 请求中包含的刷新令牌的作用域 完全相同。

发生安全事件时,授权服务器可以自动撤销刷新令牌,例如:

  • 密码更改

  • 在授权服务器注销

如果客户端已闲置一段 时间,即刷新令牌已有一段时间未用于获取新的 访问令牌,则刷新令牌应该过期。到期时间由 授权服务器自行决定。它可以是一个全局值, 也可以根据客户端策略或与 刷新令牌关联的许可(及其敏感性)来确定。

4.4. 扩展许可

客户端通过将一个绝对 URI(由授权服务器定义)指定为 令牌端点的 grant_type 参数的 值,并添加任何必要的附加参数,来使用扩展许可类型。

例如,在用户已经 在单独设备上授权客户端之后,为了使用 [RFC8628] 定义的设备授权许可 请求访问令牌, 客户端发出以下 HTTPS 请求 (仅为显示目的添加额外换行):

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

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

如果访问令牌请求有效且已获授权, 授权服务器将按照第 3.2.3 节所述颁发访问令牌以及可选的刷新 令牌。如果请求的客户端 认证失败或请求无效,授权服务器将按照第 3.2.4 节所述返回 错误响应。

5. 资源请求

客户端通过向资源服务器提交访问 令牌来访问受保护资源。资源服务器必须验证 访问令牌,并确保它尚未过期且其作用域 覆盖所请求的资源。资源 服务器用于验证访问令牌的方法 超出本规范的范围,但通常涉及 资源服务器与 授权服务器之间的交互或协调。例如,当资源服务器与 授权服务器位于同一处或属于同一系统时, 它们可以共享数据库或其他存储;当两个组件 独立运行时,它们可以使用令牌内省 [RFC7662] 或诸如 JWT [RFC9068] 这样的结构化访问令牌格式。

5.1. 持有者令牌请求

本节定义了在向资源服务器发出的资源 请求中发送持有者令牌的两种方法。客户端必须使用下面定义的两种方法之一, 并且每个请求中不得使用一种以上的方法传输令牌。

特别是,客户端不得在 URI 查询 参数中发送访问令牌, 并且资源服务器必须忽略 URI 查询参数中的访问令牌。

5.1.1. Authorization 请求标头字段

在 HTTP/1.1 [RFC7235] 定义的 Authorization 请求标头 字段中发送访问令牌时,客户端使用 Bearer 方案传输访问令牌。

例如:

 GET /resource HTTP/1.1
 Host: server.example.com
 Authorization: Bearer mF_9.B5f-4.1JqM

此方案的 Authorization 标头字段语法 遵循 第 2 节 ([RFC2617])中定义的 Basic 方案用法。 请注意,与 Basic 一样,它不符合 第 1.2 节([RFC2617])中定义的通用语法,但与 HTTP 1.1 认证 [RFC7235] 中的通用认证框架兼容,尽管为了反映现有部署, 它没有遵循其中概述的首选 实践。 Bearer 凭据的语法如下:

token68    = 1*( ALPHA / DIGIT /
                 "-" / "." / "_" / "~" / "+" / "/" ) *"="
credentials = "bearer" 1*SP token68

客户端应该使用带有 Bearer HTTP 授权方案的 Authorization 请求标头字段,以持有者令牌发出经过认证的请求。 资源服务器必须支持此方法。

如 第 11.1 节([RFC9110])所述, 字符串 bearer 不区分大小写。这意味着以下所有用法都是 Authorization 标头的有效用法:

  • Authorization: Bearer mF_9.B5f-4.1JqM

  • Authorization: bearer mF_9.B5f-4.1JqM

  • Authorization: BEARER mF_9.B5f-4.1JqM

  • Authorization: bEaReR mF_9.B5f-4.1JqM

5.1.2. 表单编码 内容参数

在 HTTP 请求内容中发送访问令牌时, 客户端使用 access_token 参数将访问令牌添加到请求内容中。除非 满足以下所有条件,否则客户端不得使用此方法:

  • HTTP 请求包含设置为 application/x-www-form-urlencoded 的 Content-Type 标头 字段。

  • 内容遵循 URL 现行标准 [WHATWG.URL] 定义的 application/x-www-form-urlencoded 内容类型的编码要求。

  • HTTP 请求内容为单部分。

  • 请求中要编码的内容必须完全 由 ASCII [USASCII] 字符组成。

  • HTTP 请求方法必须是其内容具有 已定义语义的方法。特别是,这意味着不得使用 GET 方法。

内容可以包含其他特定于请求的参数,在 这种情况下,必须使用 & 字符(ASCII 代码 38)将 access_token 参数与特定于请求的参数正确分隔。

例如,客户端使用 传输层安全发出以下 HTTP 请求:

POST /resource HTTP/1.1
Host: server.example.com
Content-Type: application/x-www-form-urlencoded

access_token=mF_9.B5f-4.1JqM

除非应用程序上下文中的参与客户端无法 访问 Authorization 请求标头字段,否则不应该 使用 application/x-www-form-urlencoded 方法。资源 服务器可以支持此方法。

5.2. 访问令牌 验证

收到访问令牌后,资源服务器必须检查 访问令牌尚未过期、已获准访问所请求的 资源、颁发时具有适当的作用域,并满足资源服务器访问受保护资源的其他策略 要求。

访问令牌通常分为两类:引用令牌或 自编码令牌。 引用令牌可以通过查询授权服务器或 在令牌数据库中查找令牌来验证,而自编码令牌 将授权信息包含在加密和/或签名的字符串中, 资源服务器可以从中提取该信息。

令牌内省 [RFC7662] 定义了查询授权服务器以检查访问令牌有效性的标准化方法。

访问令牌的 JWT 配置文件 [RFC9068] 定义了在令牌字符串中编码信息的标准化方法。

有关创建和验证访问令牌的其他注意事项,请参阅第 7.1 节。

5.3. 错误响应

如果资源访问请求失败,资源服务器应该告知 客户端该错误。错误响应的详细信息由特定令牌 类型决定,例如第 5.3.2 节中对持有者令牌的 说明。

5.3.1. WWW-Authenticate 响应标头字段

如果受保护资源请求不包含认证 凭据,或者不包含能够访问 受保护资源的访问令牌,则资源服务器必须包含 HTTP WWW-Authenticate 响应标头字段;它也可以在 响应其他条件时包含该字段。WWW-Authenticate 标头 字段使用 HTTP/1.1 [RFC7235] 定义的框架。

此令牌类型的所有质询都必须使用 auth-scheme 值 Bearer。此方案后面必须跟随一个或多个 auth-param 值。本 规范为此令牌类型使用或定义的 auth-param 属性如下。也可以使用其他 auth-param 属性。

"realm":

可以包含 realm 属性,以 按照 HTTP/1.1 [RFC7235] 中所述的方式指明 保护范围。 realm 属性不得出现多次。

"scope":

scope 属性在第 1.4.1 节中定义。 scope 属性是以空格分隔的区分大小写的作用域 值列表,用于指明访问所请求资源时 访问令牌所需的作用域。scope 值由实现 定义;不存在集中式注册表;允许的值 由授权服务器定义。scope 值的顺序 无关紧要。在某些情况下,scope 值会在请求 具有足够访问作用域、可以使用受保护资源的新访问令牌时使用。 scope 属性的使用是 可选的。scope 属性不得出现多次。 scope 值旨在供程序使用,不应 显示给最终用户。

下面给出两个示例作用域值;它们分别取自 OpenID Connect [OpenID.Messages] 和开放 认证技术 委员会(OATC)在线多媒体授权协议 [OMAP] 的 OAuth 2.0 用例:

scope="openid profile email"
scope="urn:example:channel=HBO&urn:example:rating=G,PG-13"
"error":

如果受保护资源请求包含访问 令牌但认证失败,资源服务器应该包含 error 属性,以向客户端提供访问 请求被拒绝的原因。参数值在 第 5.3.2 节中说明。

"error_description":

资源服务器可以包含 error_description 属性,为开发者提供人类可读的 说明,该说明并非用于向最终用户显示。

"error_uri":

资源服务器可以包含 error_uri 属性,其值是一个绝对 URI, 用于标识解释该错误的人类可读网页。

error、error_description 和 error_uri 属性均不得 出现多次。

scope 属性的值(在附录 A.4中规定) 不得包含用于表示作用域值的集合 %x21 / %x23-5B / %x5D-7E 以及用于 作用域值之间分隔符的 %x20 之外的字符。error 和 error_description 属性的值(分别在附录 A.7和附录 A.8中规定)不得 包含集合 %x20-21 / %x23-5B / %x5D-7E 之外的字符。 error_uri 属性的值(在附录 A.9中规定) 必须符合 URI-reference 语法,因此不得 包含集合 %x21 / %x23-5B / %x5D-7E 之外的字符。

5.3.2. 错误代码

当请求失败时,资源服务器使用适当的 HTTP 状态码(通常为 400、401、403 或 405)进行响应,并 在响应中包含以下错误代码之一:

"invalid_request":

请求缺少必需参数、包含 不支持的参数或参数值、重复相同的 参数、使用一种以上的方法包含访问 令牌,或者存在其他格式错误。资源服务器应该 使用 HTTP 400(错误请求)状态码进行响应。

"invalid_token":

所提供的访问令牌已过期、已撤销、 格式错误或 因其他原因无效。资源服务器应该使用 HTTP 401(未授权)状态码进行响应。客户端可以 请求新的访问令牌并重试受保护资源 请求。

"insufficient_scope":

请求所需的权限(作用域)高于 授予客户端并由访问令牌表示的 作用域所提供的权限。 资源服务器应该使用 HTTP 403(禁止)状态码进行响应,并且可以包含 scope 属性,其中包含访问受保护 资源所需的作用域。

扩展可以定义其他错误代码,或者指定返回上述错误代码的其他 情形。

如果请求缺少任何认证信息(例如, 客户端 不知道需要认证,或尝试使用 不受支持的认证方法),资源服务器不应该 包含错误代码或其他错误信息。

例如:

HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer realm="example"

而对于使用已过期访问令牌尝试 认证的受保护资源请求,则响应如下:

HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer realm="example",
                  error="invalid_token",
                  error_description="访问令牌已过期"

6. 可扩展性

6.1. 定义访问令牌 类型

访问令牌类型可以通过两种方式之一进行定义:在 访问令牌类型注册表中注册(遵循 第 11.1 节 ([RFC6749])中的程序),或者使用唯一的绝对 URI 作为其名称。

6.1.1. 已注册的 访问令牌类型

[RFC6750] 在 第 11.4 节([RFC6749]) 中建立了一个通用注册表,用于在 OAuth 令牌认证方案之间共享错误值。

主要为 OAuth 令牌 认证设计的新认证方案应该定义一种向客户端提供错误 状态码的机制,其中允许的错误值 注册在本规范建立的错误注册表中。

此类方案可以将有效错误代码集限制为 已注册值的子集。如果错误代码使用命名 参数返回,则参数名称应该是 error。

其他能够用于 OAuth 令牌认证, 但并非主要为此目的设计的方案,也可以以相同方式将其错误 值绑定到该注册表。

新认证方案还可以选择规定使用 error_description 和 error_uri 参数,以与本 规范中的用法类似的方式返回错误 信息。

类型名称必须符合 type-name ABNF。如果类型定义包含新的 HTTP 认证方案,则类型名称应该与 HTTP 认证方案名称(如 [RFC2617] 所定义)相同。令牌类型 example 保留用于示例。

type-name  = 1*name-char
name-char  = "-" / "." / "_" / DIGIT / ALPHA

6.1.2. 供应商特定的访问令牌类型

使用 URI 名称的类型应该仅限于 不具有普遍适用性的供应商特定实现,并且特定于 使用它们的资源服务器的实现细节。

所有其他类型都必须注册。

6.2. 定义新的端点 参数

用于授权 端点或令牌端点的新请求或响应参数,按照 第 11.2 节 ([RFC6749])中的程序,在 OAuth 参数注册表中定义和注册。

参数名称必须符合 param-name ABNF,并且参数 值语法必须定义明确(例如,使用 ABNF,或者引用 现有参数的语法)。

param-name  = 1*name-char
name-char   = "-" / "." / "_" / DIGIT / ALPHA

不具有普遍适用性且特定于 使用它们的授权服务器实现 细节的未注册供应商特定参数扩展,应该 使用不太可能与其他已注册值冲突的供应商特定前缀 (例如,以 'companyname_' 开头)。

6.3. 定义新的 授权许可类型

可以通过为新的授权许可类型分配一个 唯一的绝对 URI,以用作 grant_type 参数来定义它们。如果 扩展许可类型需要额外的令牌端点参数, 则必须按照 第 11.2 节([RFC6749])所述在 OAuth 参数注册表中注册这些参数。

6.4. 定义新的 授权端点响应类型

用于授权端点的新响应类型 按照 第 11.3 节 ([RFC6749])中的程序,在授权端点响应类型 注册表中定义和注册。响应类型 名称必须符合 response-type ABNF。

response-type  = response-name *( SP response-name )
response-name  = 1*response-char
response-char  = "_" / DIGIT / ALPHA

如果响应类型包含一个或多个空格字符(%x20),则 将其作为以空格分隔的值列表进行比较,其中 值的顺序无关紧要。只能注册一种值的顺序, 它涵盖同一值集合的所有其他排列。

例如,扩展可以定义并注册 code other_token 响应类型。注册后,相同组合不能以 other_token code 的形式注册,但这两种值都可以用于 表示同一响应类型。

6.5. 定义其他 错误代码

如果协议扩展(即访问令牌类型、 扩展参数或扩展许可类型)需要其他 错误代码与授权码许可错误 响应(第 4.1.2.1 节)、令牌错误响应(第 3.2.4 节)或 资源访问错误响应(第 5.3 节)一起使用,则可以 定义此类错误代码。

如果扩展错误代码所结合使用的扩展是 已注册访问令牌类型、已注册端点参数或 扩展许可类型,则扩展错误代码必须注册(遵循 第 11.4 节 ([RFC6749])中的程序)。与未注册扩展一起使用的错误代码 可以注册。

错误代码必须符合 error ABNF,并且在可能的情况下应该使用 标识名称作为前缀。例如,用于标识 扩展参数 example 被设置为无效值的错误,应该 命名为 example_invalid。

error      = 1*error-char
error-char = %x20-21 / %x23-5B / %x5D-7E

7. 安全注意事项

作为一个灵活且可扩展的框架,OAuth 的安全 注意事项取决于许多因素。以下各节 为实现者提供安全指南,重点针对第 2.1 节中描述的三种 客户端配置文件:Web 应用程序、 基于浏览器的应用程序和原生应用程序。

全面的 OAuth 安全模型和分析,以及 协议设计的背景,由 [RFC6819] 和 [RFC9700] 提供。

7.1. 访问令牌安全 注意事项

7.1.1. 安全威胁

以下列表列出了针对使用某种形式令牌的协议的若干常见威胁。 此威胁列表基于 NIST 特别出版物 800-63 [NIST800-63]。

7.1.1.1. 访问 令牌伪造/修改

攻击者可能生成伪造的 访问令牌,或修改现有令牌的内容(例如认证或 属性声明),从而导致资源 服务器向客户端授予不适当的访问权限。例如, 攻击者可能修改令牌以延长有效期; 恶意客户端可能修改断言,以访问 其本不应能够查看的信息。

7.1.1.2. 访问 令牌信息泄露

访问令牌可能包含认证和属性 声明,其中包含敏感信息。

如果应防止客户端观察 访问令牌的内容, 则必须应用内容加密。

由于 Cookie 默认以明文传输,因此其中包含的任何 信息都有泄露风险: 持有者令牌不得存储在可通过 明文发送的 Cookie 中。 有关 Cookie 的安全 注意事项,请参阅 [RFC6265] 的第 7 节和第 8 节。

7.1.1.3. 访问令牌 重定向

攻击者使用为一个资源服务器使用而生成的访问令牌 来获取对另一个资源 服务器的访问权限,而后者错误地认为该令牌是为其生成的。

7.1.1.4. 访问令牌 重放

攻击者试图使用一个此前已经 在该资源服务器上使用过的访问令牌。

7.1.2. 威胁缓解

通过使用数字签名保护访问令牌的内容,并遵循 签名密钥管理的最佳实践(例如定期轮换密钥),可以缓解大量威胁。

或者,持有者令牌可以包含对 授权信息的引用,而不是直接编码该信息。 使用引用可能需要资源服务器与授权服务器之间进行一次额外交互, 以将该引用解析为 授权信息。此类交互的机制 未由本规范定义,但令牌内省 [RFC7662] 定义了其中一种机制。

本文档未规定访问令牌的编码或内容; 因此,有关保证访问令牌完整性保护手段的详细建议 超出本 规范的范围。访问令牌的一种编码和 签名机制在 访问令牌的 JSON Web Token 配置文件 [RFC9068] 中进行了说明。

为了应对访问令牌重定向,授权 服务器在令牌中包含预期接收方(即 受众)的身份非常重要,通常是单个资源服务器(或资源 服务器列表)。还建议将令牌的使用限制在 特定作用域内。

第 1.5 节提供了有关 防止访问令牌泄露,以及为 客户端、资源服务器和授权服务器之间的通信 提供机密性和完整性的信息。

7.1.3. 建议 摘要

7.1.3.1. 保护 持有者令牌

客户端实现必须确保 持有者令牌不会泄露给非预期方,因为这些方将 能够使用令牌获取对受保护资源的访问权限。这 是使用持有者令牌时最主要的安全注意事项,并且 是后续所有更具体建议的基础。

7.1.3.2. 验证 TLS 证书链

客户端在向受保护资源发出请求时必须验证 TLS 证书链。 未能这样做可能使 DNS 劫持攻击能够窃取 令牌并获得非预期的访问权限。

7.1.3.3. 始终使用 TLS(https)

客户端在使用持有者令牌发出请求时必须始终使用 TLS (https)或等效的传输安全机制。 未能这样做会使令牌暴露于多种 攻击,从而可能使攻击者获得非预期的访问权限。

7.1.3.4. 不要 在 HTTP Cookie 中存储持有者令牌

实现不得将 持有者令牌存储在可通过明文发送的 Cookie 中(这是 Cookie 的默认传输模式)。确实将持有者令牌存储在 Cookie 中的实现 必须采取预防措施 防范跨站请求伪造。

7.1.3.5. 颁发 短生命周期的持有者令牌

授权服务器应该颁发 短生命周期的持有者令牌,尤其是在 向运行于 Web 浏览器或其他 可能发生信息泄露的环境中的客户端颁发令牌时。使用 短生命周期的持有者令牌可以减小它们 泄露所带来的影响。

7.1.3.6. 颁发 限定作用域的持有者令牌

授权服务器应该颁发 包含受众限制的持有者令牌,将其使用范围限定为 预期的资源服务器或资源服务器集合。

7.1.3.7. 不要 在页面 URL 中传递持有者令牌

不得在 页面 URL 中传递持有者令牌(例如作为查询字符串参数)。 相反,持有者令牌应该在采取了机密性措施的 HTTP 消息标头或 消息正文中传递。 浏览器、Web 服务器及其他软件可能无法充分 保护浏览器历史记录、Web 服务器日志及其他 数据结构中的 URL。如果在页面 URL 中传递持有者令牌, 攻击者可能能够从历史数据、日志 或其他未受保护的位置窃取它们。

7.1.4. 访问令牌 权限限制

与访问令牌关联的权限应该限制为 特定应用程序或用例所需的最低权限。 这可防止客户端超出资源所有者授权的 权限。它还可防止用户超出相应安全策略 所授权的权限。权限 限制还有助于减小访问令牌泄露的影响。

特别是,访问令牌应该限制到某些 资源服务器(受众限制),最好限制到单个资源 服务器。为实现这一点,授权服务器将 访问令牌与某些资源服务器关联,并且每个资源 服务器都有义务针对每个请求验证随该请求发送的访问 令牌是否旨在用于该特定 资源服务器。如果不是,资源服务器必须拒绝处理 相应请求。客户端和授权服务器可以分别 使用本文档和 [RFC8707] 中规定的 scope 或 resource 参数, 以 确定它们希望访问的资源服务器。

此外,访问令牌应该限制到资源服务器上的某些 资源 和操作,或某些资源上的操作。为实现这一点, 授权服务器将访问令牌与相应资源和操作 相关联,并且每个资源服务器都有义务 针对每个请求验证随该请求发送的访问令牌是否旨在用于 该特定资源上的特定操作。如果不是,资源服务器必须拒绝 处理相应请求。客户端和授权服务器可以 使用参数 scope 以及 [RFC9396] 中规定的 authorization_details 来 确定这些资源和/或操作。

7.2. 客户端认证

根据客户端注册和凭据 生命周期管理的整体过程,这可能会影响授权 服务器对特定客户端的可信程度。

例如,对动态注册客户端的认证并不能 证明客户端的身份,它仅确保向 授权服务器重复发出的请求来自同一个客户端实例。此类 客户端可以在允许请求哪些作用域方面受到限制, 或具有其他限制,例如更短的令牌生命周期。

相比之下,如果存在一个已注册应用程序,其开发者身份 已经过验证、签署了合同并获得仅用于安全后端服务的客户端密钥, 则授权 服务器可能允许此客户端请求更敏感的作用域, 或向其颁发生命周期更长的令牌。

7.3. 客户端冒充

如果机密客户端的凭据被窃取, 恶意客户端便可以冒充该客户端并获得对 受保护资源的访问权限。

授权服务器应该强制进行明确的资源所有者 认证,并向资源所有者提供有关 客户端以及所请求授权作用域和生命周期的信息。应由 资源所有者结合当前客户端的上下文审查这些信息,并 授权或拒绝请求。

授权服务器不应该在未经主动资源所有者交互的情况下自动处理重复的授权 请求, 除非认证了客户端,或者依赖其他措施 确保重复请求来自原始客户端,而 不是冒充者。

7.3.1. 冒充 原生应用

如上所述,授权 服务器不应该在没有用户同意或交互的情况下自动处理授权请求, 除非能够确认 客户端的身份。这包括用户 先前已经批准针对给定客户端 ID 的授权请求的情况—— 除非可以证明客户端的身份,否则该请求应该 按照此前没有批准过任何请求来处理。

授权服务器可以接受诸如声明的 https 方案重定向之类的措施作为 身份证明。 某些操作系统可能 提供其他平台特定的身份功能,在适当情况下也可以 接受这些功能。

7.3.2. 访问令牌 权限限制

客户端应该请求具有所需最小作用域的访问令牌。 授权服务器在决定如何满足所请求的作用域时应该考虑客户端身份, 并且可以 颁发作用域少于所请求作用域的访问令牌。

与访问令牌关联的权限应该限制为 特定应用程序或用例所需的最低权限。这 可防止客户端超出资源所有者授权的 权限。它还可防止用户超出相应安全策略 授权的权限。权限限制 还有助于减小访问令牌泄露的影响。

特别是,访问令牌应该限制到某些 资源服务器(受众限制),最好限制到单个资源 服务器。为实现这一点,授权服务器将 访问令牌与某些资源服务器相关联,并且每个资源 服务器都有义务针对每个请求验证随该请求发送的访问 令牌是否旨在用于该特定 资源服务器。如果不是,资源服务器必须拒绝处理 相应请求。客户端和授权服务器可以分别使用 [RFC8707] 中规定的 参数 scope 或 resource,以 确定它们希望访问的资源服务器。

7.4. 客户端冒充 资源所有者

资源服务器可能根据为其颁发访问令牌的 资源所有者身份,或者根据客户端凭据许可中的客户端身份来做出访问控制决定。 如果两种方式都可能适用, 根据实现的具体细节,客户端身份可能会被 误认为资源所有者身份。例如,如果客户端能够 在向授权服务器注册期间选择自己的 client_id, 恶意客户端可能将其设置为标识最终用户的值(例如,如果使用 OpenID Connect,则设置为 sub 值)。如果资源服务器无法正确 区分颁发给客户端的访问令牌与颁发给 最终用户的访问令牌,则客户端随后可能能够访问最终用户的资源。

如果授权服务器为客户端 ID 和用户 标识符使用公共命名空间,从而导致资源服务器无法区分由资源所有者授权的访问 令牌与由客户端 自身授权的访问令牌,那么如果客户端影响其 client_id 或任何其他声明会造成与真实资源所有者混淆, 授权服务器就不应该允许客户端这样做。如果 无法避免这种情况,授权服务器必须提供其他方式,让 资源服务器能够区分这两种访问令牌。

7.5. 授权码 安全注意事项

7.5.1. 授权 码注入

授权码注入是一种攻击,其中客户端在其重定向 URI 中接收到 来自攻击者的授权码,而不是来自合法授权服务器的授权 码。如果没有适当保护机制,客户端便没有 任何机制知道攻击已经发生。授权 码注入既可能导致攻击者获得对受害者账户的访问权限,也 可能导致受害者意外获得对攻击者账户的访问权限。

7.5.1.1. 对策

为了防止向 客户端注入授权码,客户端必须使用 code_challenge 和 code_verifier,并且授权服务器必须强制 使用它们,除非同时满足以下两个条件:

  • 客户端是机密客户端。

  • 在特定部署和特定 请求中,授权服务器有合理 把握确认客户端正确实现了 OpenID Connect nonce 机制。

在这种情况下,仍然建议使用并强制执行 code_challenge 和 code_verifier。

code_challenge 或 OpenID Connect nonce 值必须是 特定于事务的,并安全绑定到客户端以及启动该事务的用户代理。 如果事务导致错误,则必须为 code_challenge 或 nonce 选择新 值。

依赖客户端验证 OpenID Connect nonce 参数, 意味着授权服务器无法确认客户端 是否确实保护自身免受授权码注入攻击。 如果攻击者能够向客户端注入授权码, 客户端仍然会交换被注入的授权码并获取令牌, 并且 只会在之后验证 nonce 并发现 它不匹配时拒绝 ID 令牌。相比之下,由授权服务器强制执行 code_challenge 和 code_verifier 参数可以提供 更高的安全性, 因为授权服务器能够预先识别授权码 注入攻击,并从一开始就避免颁发任何令牌。

历史说明:虽然 PKCE [RFC7636] (其中创建了 code_challenge 和 code_verifier 参数) 最初被设计为一种 保护原生应用免受授权码外泄攻击的机制, 但各种类型的 OAuth 客户端,包括 Web 应用程序和其他机密 客户端, 都容易受到授权码注入攻击,而 code_challenge 和 code_verifier 机制可解决此问题。

7.5.2. PKCE "plain" 代码质询方法

[RFC7636] 中定义的 plain 代码质询方法,在 OAuth 2.1 中被明确禁止。 对于能够读取授权请求的攻击者 ([RFC9700] 中的攻击者 A4),plain 方法无法提供针对授权 码拦截的任何保护,因为代码验证器会以 明文形式在授权请求中传输。

支持 plain 模式的历史理由(设备缺少 密码学哈希能力)已经因 OAuth 2.1 对 TLS 1.2+ 的要求而过时, 因为后者要求支持 SHA-256 以进行证书验证。任何能够 实现 OAuth 2.1 的设备都必然支持 SHA-256。

支持 plain 代码质询 方法的授权服务器会产生一个 无法验证的降级攻击向量,因为服务器无法区分合法的 受限客户端与声称受限但被攻击者修改过的请求。

对于存在无法支持 S256 的现有客户端的部署,在停止支持旧版 授权方法之前应该 颁发延长生命周期的刷新令牌,因为刷新令牌许可(第 4.3 节) 不要求 PKCE。

7.5.3. 重用 授权码

如果授权码能够被 使用一次以上,则可能发生多种类型的攻击。

如第 4.1.3 节所述,当收到一个此前已经用于 颁发访问令牌的授权码的第二个有效请求时,授权服务器必须拒绝 该令牌请求,并撤销任何已颁发的令牌。如果攻击者能够外泄授权码 并在合法客户端之前使用它,攻击者将获得访问令牌, 而合法客户端则不会。撤销所有已颁发的令牌意味着攻击者的 令牌随后也会被撤销,从而阻止攻击继续进行。

但是,授权服务器只有在 包含授权码的请求本身也有效,包括 code_verifier 和客户端认证等所有其他参数 都有效时,才应该撤销已颁发的令牌。授权 服务器在收到包含无效参数的重放授权码时 不应该撤销任何已颁发的令牌。如果这样做, 那么能够获得授权码但无法获得客户端认证信息或 code_verifier 的攻击者 就可以在合法客户端之前发送无效的 授权码请求,并在合法客户端发出有效请求时使其 令牌被撤销,从而造成拒绝服务 的机会。

7.5.4. HTTP 307 重定向

重定向可能包含用户 凭据的请求的授权服务器不得使用 307 状态码(第 15.4.8 节([RFC9110]))进行 重定向。 如果对此类请求使用 HTTP 重定向(而不是例如 JavaScript),AS 应该使用状态 码 303(“See Other”)。

在授权端点,典型的协议流程是 AS 提示用户在表单中输入其凭据,然后 将该表单(使用 POST 方法)提交回授权 服务器。AS 检查凭据,如果成功,则将 用户代理重定向到客户端的重定向 URI。

如果使用状态码 307 进行重定向,用户代理 会通过 POST 请求将用户凭据发送给客户端。

这会将敏感凭据泄露给客户端。如果 客户端是恶意的,它可以使用这些凭据在 AS 上冒充 用户。

这种行为对开发者而言可能出乎意料,但它在 第 15.4.8 节([RFC9110])中有明确定义。该 状态码不要求用户代理 将 POST 请求重写为 GET 请求,从而丢弃 POST 请求内容中的表单数据。

在 HTTP [RFC9110] 中,只有状态码 303 明确强制将 HTTP POST 请求重写为 HTTP GET 请求。对于包括常用的 302 在内的所有其他状态码,用户 代理都可以选择不将 POST 重写为 GET 请求,因此 可能将用户凭据泄露给客户端。(不过在实践中, 大多数用户代理只会对 307 重定向表现出这种行为。)

7.6. 确保端点 真实性

与中间人攻击相关的风险通过强制使用诸如 [RFC9846] 这样的通道安全机制与授权端点和令牌端点进行通信来缓解。 有关更多详细信息,请参阅第 1.5 节。

7.7. 凭据猜测 攻击

授权服务器必须防止攻击者猜测访问 令牌、授权码、刷新令牌、资源所有者 密码和客户端凭据。

攻击者猜中生成的令牌(以及其他 非供最终用户处理的凭据)的概率必须小于或 等于 2^(-128),并且应该小于或等于 2^(-160)。

授权服务器必须使用其他手段保护 供最终用户使用的凭据。

7.8. 网络钓鱼攻击

本协议及类似协议的广泛部署可能会使最终用户 对被重定向到要求其输入密码的网站这一做法习以为常。如果最终用户在输入 凭据之前没有 仔细验证这些网站的真实性,攻击者便可能利用这种 做法窃取资源所有者的密码以及其他可通过网络钓鱼获取的 凭据,例如 OTP。

服务提供商应该尝试教育最终用户了解 网络钓鱼攻击带来的风险,并应该提供使最终用户能够轻松 确认其网站真实性的机制,例如使用 抗网络钓鱼的认证器,因为只有在 平台成功验证网站来源的情况下,抗网络钓鱼认证器 才会向用户提供用于登录特定网站的凭据。客户端 开发者应该考虑其与用户代理 (例如外部、嵌入式)交互方式的安全影响,以及 最终用户验证授权服务器 真实性的能力。

有关缓解网络钓鱼攻击风险的更多详细信息,请参阅第 1.5 节。

7.10. 跨站请求 伪造

攻击者可能尝试向受害者设备上 合法客户端的重定向 URI 注入请求,例如使 客户端访问由攻击者控制的资源。这是 一种称为跨站请求伪造(CSRF)的攻击变体。

传统对策是客户端在 state 参数中传递一个随机值, 也称为 CSRF 令牌,用于按上述方式将发往 重定向 URI 的请求与用户代理会话关联。该 对策在 第 5.3.5 节 ([RFC6819])中进行了详细说明。 code_verifier 参数或 OpenID Connect nonce 值也提供相同的保护。

当使用 code_verifier 而不是 state 或 nonce 提供 CSRF 保护时,需要 注意以下几点:

  • 客户端必须确保 AS 支持 客户端打算使用的 code_challenge_method。 如果授权服务器不支持所请求的方法, 则必须改用 state 或 nonce 提供 CSRF 保护。

  • 如果使用 state 携带应用程序状态,并且 其内容的完整性值得关注,则客户端必须保护 state 防止 篡改和置换。这可以通过将 state 的内容绑定到浏览器会话和/或使用已签名/加密的 state 值 [I-D.bradley-oauth-jwt-encoded-state] 来实现。

因此,AS 必须提供一种检测其所支持代码质询 方法的方式, 可以通过按照 [RFC8414] 提供 AS 元数据,或者提供 特定于部署的方式来确保或确定支持情况。

7.11. 点击劫持

如 第 4.4.1.9 节([RFC6819])所述, 授权 请求容易遭受点击劫持攻击,也称为用户 界面伪装。在此类攻击中,攻击者将 授权端点用户界面嵌入一个看似无害的上下文中。 用户以为自己正在与该上下文交互,例如 点击按钮,却无意中与授权 端点用户界面进行了交互。反过来也可以实现: 用户以为自己正在与授权端点交互, 却可能无意中将密码输入到攻击者提供的 覆盖在原始用户界面上的输入字段中。点击劫持 攻击可以设计得使用户几乎察觉不到攻击, 例如使用几乎不可见的 iframe 覆盖在 其他元素之上。

攻击者可以利用此向量获取用户的认证 凭据、更改授予客户端的访问作用域, 并可能访问用户的资源。

授权服务器必须防止点击劫持攻击。 [RFC6819] 中描述了多种 对策,包括使用 X-Frame-Options HTTP 响应标头字段和破框 JavaScript。除此之外,授权服务器还应该 使用内容安全策略(CSP)第 2 级 [CSP-2] 或更高版本。

为了有效,CSP 必须用于授权端点,以及 适用时用于认证用户和 授权客户端的其他端点(例如设备授权端点、登录 页面、错误页面等)。这可以防止支持 CSP 的用户代理中 未经授权的来源进行框架嵌入。客户端可以允许被 与其重定向端点所用来源不同的某些其他来源 进行框架嵌入。因此,授权服务器应该允许 管理员为特定客户端配置允许的来源, 和/或允许客户端动态注册这些来源。

使用 CSP 可以让授权服务器在单个响应标头字段中指定多个来源, 并使用灵活的 模式对它们加以限制(详见 [CSP-2])。该标准第 2 级通过结合 限制框架来源的策略(使用 frame-ancestors) 和限制允许在 HTML 页面上执行的脚本来源的策略 (使用 script-src),提供了 防御点击劫持的稳健机制。下面的清单展示了此类策略的一个非规范性 示例:

HTTP/1.1 200 OK
Content-Security-Policy: frame-ancestors https://ext.example.org:8000
Content-Security-Policy: script-src 'self'
X-Frame-Options: ALLOW-FROM https://ext.example.org:8000
...

由于某些用户代理不支持 [CSP-2],因此该技术 应该与其他技术结合使用,包括 [RFC6819] 中描述的技术,除非授权服务器明确 不支持此类旧版用户代理。即使在这种情况下,仍然应该采用其他 对策。

7.12. 注入和输入 验证

当应用程序未经净化地使用输入或其他外部 变量,并导致 应用程序逻辑被修改时,就会发生注入攻击。这可能使攻击者能够 访问应用程序设备或其数据、造成拒绝 服务,或者引入范围广泛的恶意副作用。

授权服务器和客户端必须将接收到的参数视为 可能具有恶意的外部输入,并应用适当保护, 尤其是 state 和 redirect_uri 参数的值。

7.13. 开放重定向

开放重定向器是一种端点,它将用户浏览器 转发到从查询参数获得的任意 URI。 有时会实现此类端点,例如先显示一条 消息,然后再将用户重定向到外部网站, 或者在用户被例如登录提示打断后,将用户重定向回其原本打算访问的 URL。

当 AS 或客户端具有开放 重定向器时,可能发生以下攻击。

7.13.1. 客户端作为开放 重定向器

客户端不得暴露开放重定向器。攻击者可能使用开放 重定向器生成指向客户端的 URL,并利用它们 外泄授权码,如 第 4.1.1 节([RFC9700])所述。 另一种滥用方式是生成看似指向客户端的 URL。 这可能诱骗用户信任该 URL 并在浏览器中访问它。 这可以被滥用于网络钓鱼。

为了防止开放重定向,客户端应该仅在 目标 URL 已列入白名单,或者能够认证请求的来源和完整性时才进行重定向。 OWASP [owasp_redir] 描述了针对开放重定向的对策。

7.13.2. 授权 服务器作为开放重定向器

与客户端一样,攻击者也可能试图利用用户对 授权服务器(尤其是其 URL)的信任来实施 网络钓鱼攻击。OAuth 授权服务器经常将用户重定向 到其他网站(客户端),但必须安全地执行此操作。

第 4.1.2.1 节已经通过规定在 client_id 和 redirect_uri 组合无效的情况下, 授权服务器不得自动重定向用户代理, 从而防止开放重定向。

但是,攻击者也可以利用正确注册的 重定向 URI 来实施网络钓鱼攻击。例如,攻击者可以通过动态客户端注册 [RFC7591] 注册客户端,并执行以下攻击之一:

  1. 故意发送错误的授权请求, 例如 使用无效作用域值,从而指示授权服务器将 用户代理重定向到其网络钓鱼网站。

  2. 故意发送一个有效的授权请求,其中 client_id 和 redirect_uri 由攻击者控制。用户完成认证后, 授权服务器提示用户同意该请求。如果 用户发现请求有问题并拒绝请求,授权 服务器仍然 会将用户代理重定向到网络钓鱼网站。在这种情况下,无论用户 执行什么操作,用户代理 都会被重定向到网络钓鱼网站。

  3. 故意发送有效的静默认证 请求(prompt=none), 其中 client_id 和 redirect_uri 由 攻击者控制。在这种情况下, 授权服务器会自动将用户代理重定向到 网络钓鱼网站。

授权服务器必须采取预防措施防止这些 威胁。授权服务器必须始终 先认证用户,并且除静默认证 用例外,在重定向 用户之前,在需要时提示用户输入凭据。根据其风险评估,授权服务器需要决定是否 可以信任 重定向 URI。它可以考虑内部执行的 URI 分析 或通过某些外部服务进行的分析,以评估 URI 后内容的可信度和 可信性,以及重定向 URI 和 其他客户端数据的来源。

授权服务器应该仅在信任 重定向 URI 时自动重定向 用户代理。如果不信任该 URI,授权服务器可以告知用户, 并依赖 用户做出正确决定。

7.14. 传输安全

在某些部署中,包括使用负载均衡器的部署, 到资源服务器的 TLS 连接会在真正 提供资源的服务器之前终止。这可能使令牌 在 TLS 连接终止的前端服务器与提供资源的后端服务器之间 失去保护。在 此类部署中,必须采用充分措施确保 前端和后 端服务器之间访问令牌的机密性;对令牌进行加密就是一种可行措施。

有关更多信息,请参阅 第 17.2 节([RFC9110])。

7.15. 授权服务器 混淆攻击缓解

混淆攻击针对 OAuth 客户端与 两个或更多授权服务器交互,且至少一个授权 服务器由攻击者控制的场景。例如, 攻击者可能使用动态注册将 客户端注册到自己的授权服务器,或者某个授权服务器 被攻破。

当 OAuth 客户端只能与一个授权服务器交互时,不需要 混淆 防御。但是,在 OAuth 客户端与两个 或更多授权服务器交互的场景中,客户端必须防止混淆攻击。以下 讨论两种不同的方法。

对于这两种防御方式,客户端必须为每个授权请求存储其 发送授权请求时对应的发行者,将此信息绑定到 用户代理,并检查授权响应是否来自正确的 发行者。如果适用,客户端必须确保后续访问令牌请求 发送给同一发行者。发行者通过关联的 元数据,充当流程中要使用的授权 端点和令牌端点组合的抽象标识符。如果发行者标识符 不可用,例如既未使用 OAuth 2.0 授权服务器元数据 [RFC8414] 也未使用 OpenID Connect 发现 [OpenID.Discovery],则可以改用此元组的其他唯一标识符 或元组本身。为简化表述, 下文将此类特定于部署的标识符也归入发行者(或 发行者标识符)的概念中。

注意:仅存储授权服务器 URL 不足以识别 混淆攻击。攻击者可能将未被攻破的 AS 的授权端点 URL 声明为 “自己的”AS URL,却声明一个由自己控制的令牌端点。

有关多种混淆攻击类型的详细说明,请参阅 第 4.4 节([RFC9700])。

7.15.1. 通过发行者标识 防御混淆攻击

此防御方式要求客户端比较 授权服务器在授权响应中发送给客户端的发行者标识符值。收到授权 响应时,客户端必须将收到的发行者标识符与已存储的 发行者标识符进行比较。如果不匹配,客户端必须中止 交互。

可以通过不同方式将此发行者标识符传输 给客户端:

  • 发行者信息通过响应 参数 iss 传输 (参见第 4.1.2 节)。

  • 使用 OpenID Connect 且在授权 响应中返回 ID Token 时,客户端可以评估 ID Token 中的 iss 声明。

在这两种情况下,都必须按照 [RFC9207] 评估 iss 值。

虽然这种防御方式可能需要使用额外参数来 传输 发行者信息,但它是一种稳健且相对简单的混淆攻击防御方式。

7.15.2. 通过不同重定向 URI 防御混淆攻击

对于此防御方式,客户端必须为与其交互的每个 发行者 使用不同的重定向 URI。

客户端必须通过将发行者对应的不同重定向 URI 与 接收到授权响应的 URI 进行比较,检查授权响应是否 来自正确的 发行者。如果不匹配,客户端 必须中止流程。

虽然这种防御方式建立在现有 OAuth 功能之上,但 在客户端仅注册一次便用于多个不同 发行者的场景(例如某些开放银行方案)中无法使用,并且由于它与 客户端注册紧密集成,因此更难以自动部署。

此外,攻击者可能能够通过 使用客户端分配给攻击者 AS 的重定向 URI,在“诚实的”AS 上注册一个新客户端,从而绕过 此防御提供的保护。然后攻击者可以像上面所述那样运行 攻击,将 客户端 ID 替换为其新创建客户端的客户端 ID。

因此,只有在其他选项不可用时才应该使用此防御方式。

8. 原生应用程序

原生应用程序是安装并执行在资源所有者所使用设备上的客户端 (即桌面应用程序或原生移动 应用程序)。原生应用程序需要在 安全性、平台能力和整体最终用户 体验方面给予特殊考虑。

本节中的指南主要针对原生移动应用, 而不是桌面应用。就为应用开发者提供的 与此处所述 OAuth 流程相关的能力而言,原生移动平台 比桌面平台更加成熟。虽然 本指南主要关注移动应用,但其中许多内容通常也 适用于桌面应用。

授权端点要求客户端 与资源所有者的用户代理之间进行交互。当前最佳实践是 在外部用户代理 (通常是浏览器)中执行 OAuth 授权请求,而不是在嵌入式用户代理(例如 使用 WebView 实现的用户代理)中执行。

原生应用程序可以通过多种不同方式捕获来自 授权服务器的响应, 每种方式具有不同的安全属性。例如,使用带有 “应用声明 URL”的重定向 URI,或使用 在操作系统中注册的自定义 URL 方案以调用 客户端作为处理程序,手动复制粘贴凭据, 运行本地 Web 服务器,安装用户代理扩展,或者 提供一个标识由客户端控制的服务器托管 资源的重定向 URI,而该资源又将 响应提供给原生应用程序。

过去,原生应用通常会使用嵌入式用户代理 (通常通过 WebView 实现)来处理 OAuth 授权 请求。这种方法存在许多缺点,包括宿主应用 能够复制用户凭据和 Cookie,以及用户 需要在每个应用中从头进行认证。有关使用嵌入式用户代理 处理 OAuth 的缺点的更深入分析,请参阅第 8.5.1 节。

使用系统浏览器的原生应用授权请求更加 安全,并且可以利用用户在设备上的认证状态。 能够使用浏览器中的现有认证会话 可以实现单点登录,因为用户无需在每次使用新应用时都向 授权服务器进行认证(除非 授权服务器策略要求这样做)。

无需更改 OAuth 协议本身即可支持原生应用与浏览器之间的授权流程, 因为 OAuth 授权请求和响应已经通过 URI 定义。这包括可用于应用间 通信的 URI。某些假定所有 客户端都是机密 Web 客户端的 OAuth 服务器实现,需要增加对 公共原生应用客户端以及它们所使用重定向 URI 类型的理解,以支持此最佳实践。

8.1. 原生应用的客户端认证

作为分发给多个用户的应用的一部分静态包含的秘密 并不是机密秘密,因为一个 用户可以检查其副本并得知共享秘密。基于此 原因,授权服务器不得要求原生应用客户端使用共享秘密进行客户端 认证, 因为除了客户端标识之外,这并没有提供额外价值,而客户端标识 已由 client_id 请求参数提供。

仍然要求原生应用客户端使用静态包含的共享 秘密的授权服务器,必须将该客户端视为公共 客户端(如第 2.1 节所定义),并且 不得 将该秘密视为客户端身份的证明。如果没有 额外措施,此类客户端容易遭受客户端冒充 (参见第 7.3.1 节)。

8.1.1. 原生应用客户端的注册

除非使用类似动态客户端注册 [RFC7591] 的机制来为 每个实例配置凭据,否则原生应用 被分类为公共客户端,如第 2.1 节所定义, 并且必须以此身份在授权服务器处注册。 授权服务器必须在客户端注册详细信息中记录客户端类型, 以便识别并相应地处理请求。

8.1.2. 原生应用 证明

草案规范 [I-D.ietf-oauth-attestation-based-client-auth] 定义了一种原生应用可用于获取 密钥绑定证明的机制,以向授权服务器或 资源服务器进行认证。这可以为 移动应用的身份提供更高程度的保证。

8.2. 在原生应用中使用应用间 URI 通信实现 OAuth

正如在 Web 上使用 URI 进行 OAuth 以发起 授权请求并将授权响应返回给 请求网站一样,原生应用也可以使用 URI 在设备浏览器中发起 授权请求,并将 响应返回给发起请求的原生应用。

通过采用 Web 上用于 OAuth 的相同方法, Web 上获得的优势,例如单点登录会话的易用性和 独立认证上下文的安全性,同样可以在 原生应用环境中获得。复用相同方法还可以 降低实现复杂度并提高互操作性,因为它 依赖基于标准的 Web 流程,而不是特定于某个 平台。

原生应用必须使用外部 用户代理来执行 OAuth 授权请求。这通过 在浏览器中打开授权请求(详见 第 8.3 节),并 使用能够将 授权响应返回给原生应用的重定向 URI(定义于第 8.4 节)来实现。

8.3. 从原生应用发起 授权请求

需要用户授权的原生应用按照第 4.1 节使用授权码许可类型创建授权 请求 URI, 并使用原生应用能够接收的重定向 URI。

原生应用授权 请求中重定向 URI 的作用类似于基于 Web 的授权请求。 与将授权响应返回给 OAuth 客户端服务器不同,原生应用使用的重定向 URI 会将 响应返回给应用。在不同 平台上将授权响应返回给原生应用的多种重定向 URI 选项 记录在第 8.4 节中。任何允许 应用接收 URI 并检查其参数的重定向 URI 都可行。

构造授权请求 URI 后,应用使用 平台特定的 API 在外部用户代理中打开该 URI。 通常,使用的外部用户代理是默认浏览器,即 系统上配置用于处理 http 和 https 方案 URI 的应用程序;但是,也可以使用不同的浏览器选择标准和 其他类别的外部用户代理。

此最佳实践重点将浏览器作为原生应用建议使用的外部 用户代理。也可以使用专门为用户授权设计、 能够像浏览器一样处理授权请求和响应的 外部用户代理。 其他外部用户代理,例如由 授权服务器提供的原生应用,可能满足此最佳 实践中列出的标准,包括使用相同的重定向 URI 属性,但 它们的使用超出本规范的范围。

某些平台支持一种称为“应用内浏览器 标签页”的浏览器功能,应用可以在应用 上下文中显示一个浏览器标签页而无需切换应用,同时仍保留 浏览器的关键优势,例如共享认证状态和安全上下文。 在支持该功能的平台上,出于 易用性考虑,建议应用使用应用内浏览器标签页进行 授权请求。

8.4. 在原生应用中接收 授权响应

原生应用可使用多种重定向 URI 选项来 接收来自浏览器的授权响应,其 可用性和用户体验因平台而异。

8.4.1. 声明的 "https" 方案 URI 重定向

某些操作系统,尤其是移动操作系统, 允许应用声明其控制域中的 https URI (参见 第 4.2.2 节([RFC9110]))。 当浏览器遇到已声明的 URI 时,不是在浏览器中加载页面,而是 启动原生应用,并将该 URI 作为启动参数提供给它。

原生应用可以使用此类 URI 作为重定向 URI。对于授权服务器而言,它们 与常规基于 Web 的客户端重定向 URI 无法区分。例如:

https://app.example.com/oauth2redirect/example-provider

由于仅凭重定向 URI 不足以区分公共原生 应用客户端和机密 Web 客户端,因此第 8.1.1 节要求在客户端 注册期间记录客户端类型,以使服务器能够确定客户端类型并 相应处理。

与其他原生应用重定向选项相比,应用声明的 https 方案重定向 URI 具有一些优势, 因为目标应用的身份 由操作系统向授权服务器保证。因此,在可能的情况下,原生应用应该优先使用它们,而不是 其他选项。

8.4.2. 环回 接口重定向

能够在无需特殊权限的情况下打开环回网络 接口端口的原生应用(通常是 桌面操作系统上的应用)可以使用环回接口来接收 OAuth 重定向。

环回重定向 URI 使用 http 方案,并 使用 环回 IP 字面量以及客户端正在监听的任意端口构造。

也就是说,IPv4 使用 http://127.0.0.1:{port}/{path}, IPv6 使用 http://[::1]:{port}/{path}。下面是一个使用 IPv4 环回接口和随机分配端口的重定向示例:

http://127.0.0.1:51004/oauth2redirect/example-provider

下面是一个使用 IPv6 环回接口和 随机 分配端口的重定向示例:

http://[::1]:61023/oauth2redirect/example-provider

虽然使用名称 localhost 的重定向 URI(即 http://localhost:{port}/{path})与环回 IP 重定向的工作方式类似,但不建议使用 localhost。 指定使用环回 IP 字面量的 重定向 URI,而不是 localhost,可以避免无意中监听 环回接口之外的网络接口。它也更不容易 受到客户端防火墙以及用户设备上主机名 解析配置错误的影响。

对于环回 IP 重定向 URI,授权服务器必须允许在请求时指定任意端口, 以适应 在请求时从操作 系统获取可用临时端口的客户端。

客户端不应该假定设备支持某个特定版本的 Internet Protocol。建议客户端 尝试使用 IPv4 和 IPv6 绑定环回接口, 并使用其中可用的一个。

8.4.3. 私有使用 URI 方案重定向

许多移动和桌面计算平台支持通过 URI 进行应用间 通信,方式是允许应用注册私有使用 URI 方案(有时通俗地称为“自定义 URL 方案”),例如 com.example.app。当浏览器或其他应用尝试 加载使用私有使用 URI 方案的 URI 时,会启动注册该方案的应用 来处理请求。

许多支持私有使用 URI 方案的环境并不 提供 声明某个方案并阻止其他方使用 另一个应用方案的机制。因此,使用私有使用 URI 方案的客户端容易受到针对其重定向 URI 的潜在攻击, 所以只有在前面提到的更安全 选项不可用时才应该使用此选项。

要使用私有使用 URI 方案重定向执行授权请求,原生应用会使用标准 授权请求启动浏览器,但其重定向 URI 使用 已在操作系统中注册的私有使用 URI 方案。

选择与应用关联的 URI 方案时,应用必须使用 基于其控制的域名的 URI 方案,并以 反向顺序表示,如 第 3.8 节([RFC7595])针对 私有使用 URI 方案所建议。

例如,控制域名 app.example.com 的应用可以使用 com.example.app 作为其方案。某些授权 服务器根据域名分配客户端标识符,例如 client1234.usercontent.example.net,在以相同方式反转后,也可以将其用作 方案的域名。然而,像 myapp 这样的 方案不满足此要求,因为 它并非基于域名。

当同一发布者拥有多个应用时,必须注意 确保该组中的每个方案都是唯一的。在使用 基于反向域名的应用标识符的平台上,这些 标识符可以重新用作 OAuth 重定向的私有使用 URI 方案,以帮助避免此问题。

按照 第 3.2 节([RFC3986])的要求,由于 私有使用 URI 方案重定向不存在 命名机构,因此方案组成部分之后只出现 一个斜杠(/)。使用私有使用 URI 方案的完整 重定向 URI 示例如下:

com.example.app:/oauth2redirect/example-provider

当授权服务器完成请求时,它会像往常一样重定向到 客户端的重定向 URI。由于 重定向 URI 使用私有使用 URI 方案,因此 操作系统会启动原生应用,并将该 URI 作为 启动参数传入。然后,原生应用使用常规流程处理 授权响应。

8.5. 原生应用中的安全 注意事项

8.5.1. 原生应用中的嵌入式用户 代理

嵌入式用户代理在技术上可以用于授权原生 应用。根据定义,这些嵌入式用户代理对于授权服务器的第三方而言并不安全, 因为托管 嵌入式用户代理的应用可以访问用户完整的认证 凭据,而不仅仅是原本授予 该应用的 OAuth 授权许可。它们通常还会受到操作系统 的沙箱限制,并且依赖 Web 来源的 WebAuthn 等机制会被禁用。

在典型的基于 WebView 的嵌入式用户代理实现中, 宿主应用程序可以记录登录 表单中输入的每次按键以捕获用户名和密码,自动提交表单 以绕过用户同意,并复制会话 Cookie,使用它们 以用户身份执行经过认证的操作。

即使由与 授权服务器属于同一方的受信任应用使用,嵌入式用户代理也违反最小 权限原则,因为它们可以访问比 实际所需更强大的凭据,从而可能扩大攻击面。

鼓励用户在没有浏览器通常具有的地址栏和可见证书验证 功能的嵌入式用户代理中输入凭据, 会使用户无法知道 自己是否正在登录合法网站;即使确实如此,这也会 训练用户认为无需先验证网站便输入凭据是可以接受的。

除了安全问题之外,嵌入式用户代理不会与其他应用或浏览器共享 认证状态,因此 用户必须为每个授权请求登录,这通常 被认为是较差的用户体验。

8.5.2. 原生应用中的伪造外部 用户代理

发起授权请求的原生应用对 用户界面具有很大程度的控制权,并可能 呈现伪造的外部用户代理,即 被伪装成外部用户代理的嵌入式用户代理。

当所有良性参与方都使用外部用户代理时,其优势 在于安全专家能够检测恶意参与方,因为 任何伪造外部用户代理的行为都可以被证明是恶意的。另一方面, 如果良性和恶意参与方都使用嵌入式用户代理, 恶意参与方无需伪造任何东西,因此更难被发现。 一旦检测到恶意应用,就可能利用这些 信息在恶意软件扫描 软件中将应用签名列入黑名单、执行移除操作(对于由应用 商店分发的应用)以及采取其他措施来减少 恶意应用的影响和传播。

授权服务器还可以通过要求一种仅真正的外部 用户代理可用的认证因素,直接防御伪造的外部 用户代理。

在使用应用内浏览器标签页时特别关注自身安全的用户, 还可以采取额外步骤,从应用内浏览器标签页中 在完整浏览器里打开请求,并在那里完成 授权,因为大多数应用内 浏览器标签页模式的实现都提供此功能。

8.5.3. 原生应用中的恶意 外部用户代理

如果恶意应用能够将自己配置为操作系统中 https 方案 URI 的默认处理程序, 它就能够 拦截使用默认浏览器的授权请求,并 滥用这一受信任位置实施网络钓鱼等恶意行为。

这种攻击并不限于 OAuth;以 此方式配置的恶意应用会给用户带来一种超出 原生应用 OAuth 使用范围的普遍且持续的风险。许多操作系统通过 要求用户执行明确操作才能更改 http 和 https 方案 URI 的默认处理程序来缓解此 问题。

8.5.4. 原生应用中的环回 重定向注意事项

环回接口重定向 URI 可以使用 http 方案(即不使用 TLS)。对于环回 接口重定向 URI,这是可以接受的,因为 HTTP 请求永远不会离开设备。

客户端应该仅在开始 授权请求时打开网络端口,并在响应返回后关闭它。

客户端应该仅监听环回网络接口,以 避免其他网络参与方的干扰。

客户端应该使用环回 IP 字面量,而不是字符串 localhost, 如第 8.4.2 节所述。

9. 基于浏览器的应用

基于浏览器的应用是在 Web 浏览器中运行的客户端,通常 使用 JavaScript 编写,也称为“单页应用”。此类应用 具有与原生应用类似的特殊安全注意事项。

待办:在基于浏览器的应用 BCP 最终定稿后,引入其中的规范性文本。

10. 与 OAuth 2.0 的差异

本草案整合了 OAuth 2.0 [RFC6749]、 原生应用的 OAuth 2.0 [RFC8252]、 代码交换证明密钥 [RFC7636]、 基于浏览器的应用的 OAuth 2.0 [I-D.ietf-oauth-browser-based-apps]、 OAuth 安全最佳当前实践 [RFC9700] 以及持有者令牌用法 [RFC6750]中的功能。

如果后续草案更新或废止了原始 [RFC6749] 中的功能,则本草案中的该功能会 根据后续草案所述的规范性 更改进行更新,或者被完全移除。

下面列出了与 OAuth 2.0 相比的非规范性更改列表:

10.1. 移除 OAuth 2.0 隐式许可

OAuth 2.0 隐式许可已从 OAuth 2.1 中省略,因为它已在 [RFC9700] 中被弃用。

移除隐式许可的目的是不再在授权响应中颁发访问令牌, 因为此类令牌容易遭到泄露 和注入,并且无法对客户端施加发送方约束。 客户端通过使用 response_type=token 参数来指示此行为。 OAuth 2.1 中不再定义 response_type 参数的此值。

移除 response_type=token 不会影响其他 从授权端点返回其他工件的扩展 响应类型,例如 [OpenID.Connect] 定义的 response_type=id_token。

10.2. 令牌请求中的重定向 URI 参数

在 OAuth 2.0 中,授权码 流程中的令牌端点请求(第 4.1.3 节([RFC6749]))包含一个 可选的 redirect_uri 参数。该参数旨在防止 授权码注入攻击,并且如果原始授权请求中发送了 redirect_uri 参数, 则必须包含该参数。只有在为特定 客户端注册了多个重定向 URI 时,授权请求才要求 redirect_uri 参数。然而在实践中,许多授权服务器实现即使只注册了一个重定向 URI, 也要求授权请求包含 redirect_uri 参数,从而导致令牌端点 同样要求 redirect_uri 参数。

在 OAuth 2.1 中,授权码注入由 code_challenge 和 code_verifier 参数防止,因此在令牌请求中包含 redirect_uri 参数不再具有作用。因此,该参数已被移除。

为了使希望同时支持 OAuth 2.0 和 OAuth 2.1 客户端的授权服务器保持向后兼容,授权服务器必须允许客户端在 令牌请求(第 4.1.3 节)中发送 redirect_uri 参数,并且必须按照 [RFC6749] 中所述强制执行该参数。授权服务器可以 使用请求中的 client_id 来确定是否对 已知将使用旧版 OAuth 2.0 行为的特定客户端强制执行此行为。

仅遵循 OAuth 2.1 建议的客户端不会在 令牌请求中发送 redirect_uri,因此它将无法与 期望令牌请求中包含该参数的授权服务器兼容。

11. IANA 注意事项

本文档不需要任何 IANA 操作。

所有引用的注册表均由 [RFC6749] 以及本工作所基于的相关文档定义。本规范 不要求对这些注册表进行任何更改。

12. 参考文献

12.1. 规范性参考文献

[BCP195]
Saint-Andre, P.,“安全使用传输层安全(TLS)的建议”,。
[RFC2119]
Bradner, S.,“用于 RFC 中指示要求级别的关键词”,BCP 14, RFC 2119,DOI 10.17487/RFC2119,, <https://www.rfc-editor.org/info/rfc2119>。
[RFC2617]
Franks, J.,Hallam-Baker, P., Hostetler, J.,Lawrence, S., Leach, P.,Luotonen, A. 和 L. Stewart,“HTTP 认证: Basic 和 Digest 访问认证”,RFC 2617,DOI 10.17487/RFC2617,,<https://www.rfc-editor.org/info/rfc2617>。
[RFC3629]
Yergeau, F.,“UTF-8,ISO 10646 的一种转换 格式”,STD 63,RFC 3629,DOI 10.17487/RFC3629,, <https://www.rfc-editor.org/info/rfc3629>。
[RFC3986]
Berners-Lee, T.,Fielding, R. 和 L. Masinter,“统一资源 标识符(URI):通用语法”,STD 66,RFC 3986,DOI 10.17487/RFC3986,, <https://www.rfc-editor.org/info/rfc3986>。
[RFC4949]
Shirey, R.,“互联网安全 术语表,第 2 版”,FYI 36,RFC 4949,DOI 10.17487/RFC4949,, <https://www.rfc-editor.org/info/rfc4949>。
[RFC5234]
Crocker, D.,编 和 P. Overell,“语法规范的扩充 BNF: ABNF”,STD 68,RFC 5234,DOI 10.17487/RFC5234,,<https://www.rfc-editor.org/info/rfc5234>。
[RFC6749]
Hardt, D.,编,“OAuth 2.0 授权框架”,RFC 6749,DOI 10.17487/RFC6749,,<https://www.rfc-editor.org/info/rfc6749>。
[RFC6750]
Jones, M. 和 D. Hardt,“OAuth 2.0 授权框架:持有者令牌用法”, RFC 6750,DOI 10.17487/RFC6750,, <https://www.rfc-editor.org/info/rfc6750>。
[RFC7235]
Fielding, R.,编 和 J. Reschke, 编,“超文本传输协议(HTTP/1.1): 认证”,RFC 7235,DOI 10.17487/RFC7235,,<https://www.rfc-editor.org/info/rfc7235>。
[RFC7521]
Campbell, B.,Mortimore, C., Jones, M. 和 Y. Goland, “OAuth 2.0 客户端认证和 授权许可的断言框架”,RFC 7521,DOI 10.17487/RFC7521,,<https://www.rfc-editor.org/info/rfc7521>。
[RFC7523]
Jones, M.,Campbell, B. 和 C. Mortimore,“OAuth 2.0 客户端认证和授权许可的 JSON Web Token(JWT) 配置文件”,RFC 7523,DOI 10.17487/RFC7523,, <https://www.rfc-editor.org/info/rfc7523>。
[RFC7595]
Thaler, D.,编,Hansen, T. 和 T. Hardie,“URI 方案的指南和 注册程序”,BCP 35, RFC 7595,DOI 10.17487/RFC7595,, <https://www.rfc-editor.org/info/rfc7595>。
[RFC8174]
Leiba, B.,“RFC 2119 关键词中大写与 小写的歧义”,BCP 14,RFC 8174,DOI 10.17487/RFC8174,, <https://www.rfc-editor.org/info/rfc8174>。
[RFC8252]
Denniss, W. 和 J. Bradley, “原生应用的 OAuth 2.0”,BCP 212,RFC 8252,DOI 10.17487/RFC8252,, <https://www.rfc-editor.org/info/rfc8252>。
[RFC8259]
Bray, T.,编,“JavaScript Object Notation(JSON)数据交换格式”,STD 90, RFC 8259,DOI 10.17487/RFC8259,, <https://www.rfc-editor.org/info/rfc8259>。
[RFC9110]
Fielding, R.,编,Nottingham, M., 编 和 J. Reschke,编,“HTTP 语义”,STD 97,RFC 9110,DOI 10.17487/RFC9110,, <https://www.rfc-editor.org/info/rfc9110>。
[RFC9111]
Fielding, R.,编,Nottingham, M., 编 和 J. Reschke,编,“HTTP 缓存”,STD 98,RFC 9111,DOI 10.17487/RFC9111,, <https://www.rfc-editor.org/info/rfc9111>。
[RFC9207]
Meyer zu Selhausen, K. 和 D. Fett,“OAuth 2.0 授权服务器发行者 标识”,RFC 9207,DOI 10.17487/RFC9207,,<https://www.rfc-editor.org/info/rfc9207>。
[RFC9700]
Lodderstedt, T.,Bradley, J., Labunets, A. 和 D. Fett, “OAuth 2.0 安全最佳当前实践”,BCP 240,RFC 9700,DOI 10.17487/RFC9700,,<https://www.rfc-editor.org/info/rfc9700>。
[RFC9846]
Rescorla, E.,“传输层 安全(TLS)协议 1.3 版”,RFC 9846, DOI 10.17487/RFC9846,,<https://www.rfc-editor.org/info/rfc9846>。
[USASCII]
Institute, A. N. S.,“编码字符 集——7 位美国信息交换标准代码,ANSI X3.4”, 。
[W3C.REC-xml-20081126]
Bray, T.,Paoli, J.,Sperberg-McQueen, C. M.,Maler, E. 和 F. Yergeau,“可扩展标记语言”,,<https://www.w3.org/TR/REC-xml/REC-xml-20081126.xml>。
[WHATWG.CORS]
WHATWG,“Fetch 标准:CORS 协议”,, <https://fetch.spec.whatwg.org/#http-cors-protocol>。
[WHATWG.URL]
WHATWG,“URL”,,<https://url.spec.whatwg.org/>。

12.2. 资料性参考文献

[CSP-2]
“内容安全策略第 2 级”,,<https://www.w3.org/TR/CSP2>。
[I-D.bradley-oauth-jwt-encoded-state]
Bradley, J.,Lodderstedt, T. 和 H. Zandbelt,“使用 JWT 在 OAuth 2 state 参数中编码声明”,进行中的 工作,互联网草案, draft-bradley-oauth-jwt-encoded-state-09,,<https://datatracker.ietf.org/doc/html/draft-bradley-oauth-jwt-encoded-state-09>。
[I-D.ietf-oauth-attestation-based-client-auth]
Looker, T.,Bastian, P. 和 C. Bormann,“基于证明的 OAuth 2.0 客户端认证”,进行中的 工作,互联网草案, draft-ietf-oauth-attestation-based-client-auth-10,,<https://datatracker.ietf.org/doc/html/draft-ietf-oauth-attestation-based-client-auth-10>。
[I-D.ietf-oauth-browser-based-apps]
Parecki, A.,De Ryck, P. 和 D. Waite,“基于浏览器的 应用的 OAuth 2.0”,进行中的工作,互联网草案,draft-ietf-oauth-browser-based-apps-27,,<https://datatracker.ietf.org/doc/html/draft-ietf-oauth-browser-based-apps-27>。
[I-D.ietf-oauth-client-id-metadata-document]
Parecki, A. 和 E. Smith, “OAuth 客户端 ID 元数据文档”,进行中的工作,互联网草案, draft-ietf-oauth-client-id-metadata-document-02,,<https://datatracker.ietf.org/doc/html/draft-ietf-oauth-client-id-metadata-document-02>。
[I-D.ietf-oauth-rfc7523bis]
Jones, M. B.,Campbell, B., Mortimore, C. 和 F. Skokan, “OAuth 2.0 JSON Web Token(JWT)客户端认证和 基于断言的授权许可更新”,进行中的 工作,互联网草案, draft-ietf-oauth-rfc7523bis-11,,<https://datatracker.ietf.org/doc/html/draft-ietf-oauth-rfc7523bis-11>。
[NIST800-63]
Burr, W.,Dodson, D.,Newton, E.,Perlner, R.,Polk, T.,Gupta, S. 和 E. Nabbus,“NIST 特别出版物 800-63-1,信息安全”,,<http://csrc.nist.gov/publications/>。
[OMAP]
Huff, J.,Schlacht, D.,Nadalin, A.,Simmons, J.,Rosenberg, P.,Madsen, P.,Ace, T.,Rickelton-Abdi, C. 和 B. Boyer,“在线多媒体 授权协议:互联网多媒体资源授权访问的行业标准”,,<https://www.svta.org/product/online-multimedia-authorization-protocol/>。
[OpenID.Connect]
Sakimura, N.,Bradley, J., Jones, M.,de Medeiros, B. 和 C. Mortimore,“OpenID Connect Core 1.0(纳入勘误集 2)”,,<https://openid.net/specs/openid-connect-core-1_0.html>。
[OpenID.Discovery]
Sakimura, N.,Bradley, J., Jones, M. 和 E. Jay,“OpenID Connect Discovery 1.0(纳入勘误集 2)”,,<https://openid.net/specs/openid-connect-discovery-1_0.html>。
[OpenID.Messages]
Sakimura, N.,Bradley, J., Jones, M.,de Medeiros, B., Mortimore, C. 和 E. Jay, “OpenID Connect Messages 1.0”,,<http://openid.net/specs/openid-connect-messages-1_0.html>。
[owasp_redir]
“OWASP 速查表系列——未验证的重定向和 转发”,,<https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html>。
[RFC6265]
Barth, A.,“HTTP 状态管理 机制”,RFC 6265,DOI 10.17487/RFC6265,,<https://www.rfc-editor.org/info/rfc6265>。
[RFC6819]
Lodderstedt, T.,编,McGloin, M. 和 P. Hunt,“OAuth 2.0 威胁模型和安全注意事项”,RFC 6819,DOI 10.17487/RFC6819,,<https://www.rfc-editor.org/info/rfc6819>。
[RFC7009]
Lodderstedt, T.,编,Dronia, S. 和 M. Scurtescu,“OAuth 2.0 令牌撤销”,RFC 7009,DOI 10.17487/RFC7009,,<https://www.rfc-editor.org/info/rfc7009>。
[RFC7519]
Jones, M.,Bradley, J. 和 N. Sakimura,“JSON Web Token (JWT)”,RFC 7519,DOI 10.17487/RFC7519,, <https://www.rfc-editor.org/info/rfc7519>。
[RFC7591]
Richer, J.,编,Jones, M., Bradley, J.,Machulak, M. 和 P. Hunt,“OAuth 2.0 动态客户端 注册协议”,RFC 7591,DOI 10.17487/RFC7591,,<https://www.rfc-editor.org/info/rfc7591>。
[RFC7592]
Richer, J.,编,Jones, M., Bradley, J. 和 M. Machulak, “OAuth 2.0 动态客户端注册管理协议”, RFC 7592,DOI 10.17487/RFC7592,, <https://www.rfc-editor.org/info/rfc7592>。
[RFC7636]
Sakimura, N.,编,Bradley, J. 和 N. Agarwal,“OAuth 公共客户端的 代码交换证明密钥”,RFC 7636,DOI 10.17487/RFC7636,,<https://www.rfc-editor.org/info/rfc7636>。
[RFC7662]
Richer, J.,编,“OAuth 2.0 令牌 内省”,RFC 7662,DOI 10.17487/RFC7662,,<https://www.rfc-editor.org/info/rfc7662>。
[RFC8414]
Jones, M.,Sakimura, N. 和 J. Bradley,“OAuth 2.0 授权 服务器元数据”,RFC 8414,DOI 10.17487/RFC8414,,<https://www.rfc-editor.org/info/rfc8414>。
[RFC8628]
Denniss, W.,Bradley, J., Jones, M. 和 H. Tschofenig, “OAuth 2.0 设备授权许可”,RFC 8628,DOI 10.17487/RFC8628,, <https://www.rfc-editor.org/info/rfc8628>。
[RFC8705]
Campbell, B.,Bradley, J., Sakimura, N. 和 T. Lodderstedt,“OAuth 2.0 相互 TLS 客户端认证 和证书绑定访问令牌”,RFC 8705, DOI 10.17487/RFC8705,,<https://www.rfc-editor.org/info/rfc8705>。
[RFC8707]
Campbell, B.,Bradley, J. 和 H. Tschofenig,“OAuth 2.0 的资源 指示符”,RFC 8707,DOI 10.17487/RFC8707,,<https://www.rfc-editor.org/info/rfc8707>。
[RFC9068]
Bertocci, V.,“OAuth 2.0 访问令牌的 JSON Web Token(JWT) 配置文件”,RFC 9068, DOI 10.17487/RFC9068,,<https://www.rfc-editor.org/info/rfc9068>。
[RFC9112]
Fielding, R.,编,Nottingham, M., 编 和 J. Reschke,编,“HTTP/1.1”,STD 99,RFC 9112,DOI 10.17487/RFC9112,, <https://www.rfc-editor.org/info/rfc9112>。
[RFC9126]
Lodderstedt, T.,Campbell, B., Sakimura, N.,Tonge, D. 和 F. Skokan,“OAuth 2.0 推送 授权请求”,RFC 9126,DOI 10.17487/RFC9126,,<https://www.rfc-editor.org/info/rfc9126>。
[RFC9396]
Lodderstedt, T.,Richer, J. 和 B. Campbell,“OAuth 2.0 丰富 授权请求”,RFC 9396,DOI 10.17487/RFC9396,,<https://www.rfc-editor.org/info/rfc9396>。
[RFC9449]
Fett, D.,Campbell, B.,Bradley, J.,Lodderstedt, T., Jones, M. 和 D. Waite,“OAuth 2.0 持有证明演示(DPoP)”,RFC 9449,DOI 10.17487/RFC9449,, <https://www.rfc-editor.org/info/rfc9449>。
[RFC9470]
Bertocci, V. 和 B. Campbell, “OAuth 2.0 逐步增强认证质询协议”,RFC 9470,DOI 10.17487/RFC9470,, <https://www.rfc-editor.org/info/rfc9470>。
[W3C.REC-html401-19991224]
Hors, A. L.,编,Raggett, D., 编 和 I. Jacobs,编,“HTML 4.01 规范”,W3C REC REC-html401-19991224,W3C REC-html401-19991224, ,<https://www.w3.org/TR/1999/REC-html401-19991224/>。

附录 A. 扩充巴科斯-瑙尔形式 (ABNF)语法

本节使用 [RFC5234] 的表示法,为本规范中定义的元素提供扩充巴科斯-瑙尔形式(ABNF)语法 说明。下面的 ABNF 以 Unicode 码位 [W3C.REC-xml-20081126] 定义; 这些字符通常 使用 UTF-8 编码。各元素按照首次定义的顺序列出。

下面的一些定义使用 [RFC3986] 中的“URI-reference”定义。

下面的一些定义使用这些通用定义:

VSCHAR     = %x20-7E
NQCHAR     = %x21 / %x23-5B / %x5D-7E
NQSCHAR    = %x20-21 / %x23-5B / %x5D-7E

A.1. "client_id" 语法

client_id 元素定义于第 2.4.1 节:

client-id     = *VSCHAR

A.2. "client_secret" 语法

client_secret 元素定义于第 2.4.1 节:

client-secret = *VSCHAR

A.3. "response_type" 语法

response_type 元素定义于第 4.1.1 节和第 6.4 节:

response-type = response-name *( SP response-name )
response-name = 1*response-char
response-char = "_" / DIGIT / ALPHA

A.4. "scope" 语法

scope 元素定义于第 1.4.1 节:

 scope       = scope-token *( SP scope-token )
 scope-token = 1*NQCHAR

A.5. "state" 语法

state 元素定义于第 4.1.1 节、第 4.1.2 节以及第 4.1.2.1 节:

 state      = 1*VSCHAR

A.6. "redirect_uri" 语法

redirect_uri 元素定义于第 4.1.1 节和第 4.1.3 节:

 redirect-uri      = URI-reference

A.7. "error" 语法

error 元素定义于第 4.1.2.1 节、第 3.2.4 节 和第 5.3 节:

 error             = 1*NQSCHAR

A.8. "error_description" 语法

error_description 元素定义于第 4.1.2.1 节、 第 3.2.4 节和第 5.3 节:

 error-description = 1*NQSCHAR

A.9. "error_uri" 语法

error_uri 元素定义于第 4.1.2.1 节、第 3.2.4 节 和第 5.3 节:

 error-uri         = URI-reference

A.10. "grant_type" 语法

grant_type 元素定义于第 3.2.2 节:

 grant-type = grant-name / URI-reference
 grant-name = 1*name-char
 name-char  = "-" / "." / "_" / DIGIT / ALPHA

A.11. "code" 语法

code 元素定义于第 4.1.3 节:

 code       = 1*VSCHAR

A.12. "access_token" 语法

access_token 元素定义于第 3.2.3 节:

 access-token = 1*VSCHAR

A.13. "token_type" 语法

token_type 元素定义于第 3.2.3 节和第 6.1 节:

 token-type = type-name / URI-reference
 type-name  = 1*name-char
 name-char  = "-" / "." / "_" / DIGIT / ALPHA

A.14. "expires_in" 语法

expires_in 元素定义于第 3.2.3 节:

 expires-in = 1*DIGIT

A.15. "refresh_token" 语法

refresh_token 元素定义于第 3.2.3 节和第 4.3 节:

 refresh-token = 1*VSCHAR

A.16. 端点参数 语法

新端点参数的语法定义于第 6.2 节:

 param-name = 1*name-char
 name-char  = "-" / "." / "_" / DIGIT / ALPHA

A.17. "code_verifier" 语法

code_verifier 的 ABNF 如下。

code-verifier = 43*128unreserved
unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
ALPHA = %x41-5A / %x61-7A
DIGIT = %x30-39

A.18. "code_challenge" 语法

code_challenge 的 ABNF 如下。

code-challenge = 43*128unreserved
unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
ALPHA = %x41-5A / %x61-7A
DIGIT = %x30-39

附录 B. 使用 application/x-www-form-urlencoded 媒体类型

在 [RFC6749] 发布时, application/x-www-form-urlencoded 媒体类型定义于 [W3C.REC-html401-19991224] 的第 17.13.4 节,但尚未在 IANA MIME 媒体类型注册表 (http://www.iana.org/assignments/media-types)中注册。 此外,该 定义并不完整,因为它没有考虑非 US-ASCII 字符。

为了在使用此媒体 类型生成内容时解决这一缺陷,名称和值必须首先使用 UTF-8 字符 编码方案 [RFC3629] 进行编码;得到的 八位字节序列随后 需要进一步使用 [W3C.REC-html401-19991224] 中定义的转义规则进行编码。

使用此媒体类型解析内容中的数据时,通过反转名称/值编码得到的名称和 值因此 需要被视为八位字节序列,并使用 UTF-8 字符编码方案进行解码。

例如,由以下六个 Unicode 码位组成的值: (1) U+0020(空格)、(2) U+0025(百分号)、 (3) U+0026(与号)、(4) U+002B(加号)、 (5) U+00A3(英镑符号)以及 (6) U+20AC(欧元符号),将被编码 为下面的八位字节序列(使用十六进制表示法):

20 25 26 2B C2 A3 E2 82 AC

然后在内容中表示为:

+%25%26%2B%C2%A3%E2%82%AC

附录 C. 序列化

本规范中的各种消息使用下面所述方法之一进行序列化。 本节说明这些序列化方法的语法;其他章节说明 何时可以以及必须使用它们。请注意,并非所有方法都能用于所有消息。

C.1. 查询字符串 序列化

为了使用查询字符串序列化对参数进行序列化, 客户端使用 [WHATWG.URL] 定义的 application/x-www-form-urlencoded 格式,将参数和值添加到 URL 的查询组成部分中来构造字符串。查询字符串序列化 通常用于 HTTP GET 请求。

C.2. 表单编码 序列化

参数及其值通过使用附录 B定义的 application/x-www-form-urlencoded 格式,将参数名称和值添加到 HTTP 请求的实体正文中来进行表单序列化。表单序列化通常用于 HTTP POST 请求。

C.3. JSON 序列化

通过在最高结构层级添加每个参数,将参数序列化为 JSON [RFC8259] 对象结构。 参数名称和字符串值表示为 JSON 字符串。 数值表示为 JSON 数字。布尔值表示为 JSON 布尔值。除非另有规定,省略的参数以及没有值的参数应该从对象中省略,而 不应表示为 JSON null 值。参数可以将 JSON 对象或 JSON 数组作为其值。参数的顺序无关紧要,并且可以变化。

附录 D. 扩展

下面列出发布时已广泛确立的扩展:

附录 E. 致谢

本规范是 OAuth 工作组的成果,其起点 基于以下规范的内容:OAuth 2.0 授权框架(RFC 6749)、 原生应用的 OAuth 2.0(RFC 8252)、OAuth 安全最佳当前实践以及基于浏览器的应用的 OAuth 2.0。 编辑者谨向所有参与创建这些 本规范所基于规范的人士表示感谢。

编辑者还要感谢以下人士提供的想法、 反馈、更正和措辞,这些贡献帮助塑造了本版规范:Andrii Deinega、 Bob Hamburg、Brian Campbell、Daniel Fett、Deng Chao、Emelia Smith、Falko、Filip Skokan、Goutam Adwant、 Joseph Heenan、Justin Richer、Karsten Meyer zu Selhausen、Michael Jones、Michael Peck、Roberto Polli、 Tim Würtele 和 Vittorio Bertocci。

围绕本规范的讨论还曾在 2021 年和 2022 年的 OAuth 安全研讨会上 进行。作者感谢研讨会组织者(Guido Schmitz、Steinar Noem 和 Daniel Fett)举办了一个有利于协作和社区意见交流的活动。

附录 F. 文档历史

[[ 将从最终规范中移除 ]]

-16

-15

-14

-13

-12

-11

-10

-09

-08

-07

-06

-05

-04

-03

-02

-01

-00

作者地址

Dick Hardt
Hellō
Aaron Parecki
Okta
Torsten Lodderstedt
SPRIND