[翻译] OAuth 2.1 授权框架草案第 9 版

原文地址: https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-09

# 简介

为了让团队更深入的理解 OAuth 认证框架, 我们学习了 IETF 上的 OAuth 2.1 草案的第 9 版, 并在学习的过程中留下了这篇译文. 为了让更多的同学也能较为全面的了解 OAuth 2.1 授权框架规范, 我们决定将这篇译文公开给大家进行参考.

本文中引用了大量其他 RFC 文档, 处于工作量方面的考虑, 没有在译文中逐一添加这些外部链接的跳转方式. 有需要的同学可以通过 RFC ID 自行搜索相关文档进一步学习.

# 正文

发布时间: 2023-07-10

过期时间: 2024-01-11

OAuth 2.1 授权框架草案



# 摘要 Abstract

OAuth 2.1 授权框架使应用程序能够代表资源所有者获取对受保护资源的有限访问权限, 方法是协调资源所有者与授权服务之间的审批交互, 或者允许应用程序代表自己获取访问权限.

此规范替换并淘汰了 RFC 6749 中描述的 OAuth 2.0 授权框架和 RFC 6750 中描述的持有者令牌 Bearer Token 用法.

# 讨论场地 Discussion Venues

对本文档的讨论在OAuth工作组邮件列表(oauth@ietf.org)上进行, 该邮件列表存档于 https://mailarchive.ietf.org/arch/browse/oauth/ (opens new window) .

该草案的源文件和相关问题可以在以下位置找到: https://github.com/oauth-wg/oauth-v2-1 (opens new window) .

# 当前状态 Status of This Memo

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

互联网草案是互联网工程 (IETF) 的工作文件. 请注意, 其他团体也可能会分发作为互联网草案的工作文件. 当前互联网草案列表位于 https://datatracker.ietf.org/drafts/current/ .

互联网草案是有效期最长为六个月的文件草案, 可以随时被其他文件更新, 替换或废弃.

该互联网草案将于 2024 年 1 月 11 日到期.

版权所有 (c) 2023 IETF 信托和被确定为文档作者的人员. 保留所有权利.

本文档受 BCP 78 和 IETF 信托与 IETF 文档相关的法律规定 (https://trustee.ietf.org/license-info) 的约束, 该条款在本文档发布之日生效. 请仔细阅读这些文件, 因为它们描述了您对本文档的权利和限制. 从本文档中提取的代码组件必须包括修订的 BSD 许可证文本, 如信托法律规定的第 4.e 节所述, 并且不提供修订后的 BSD 许可证中所述的保证.

# 1. 简介 Introduction

OAuth 通过将客户端的角色与资源所有者的角色分开, 向客户端-服务器身份验证模型引入了授权层. 在 OAuth 中, 客户端请求访问由资源所有者控制并由资源服务器托管的资源. 客户端通过访问令牌 Access Token, 而不是使用资源所有者的凭据 Credential 来访问受保护的资源, 该令牌表示一组特定的访问属性, 例如范围和生存期. 访问令牌由授权服务器在资源所有者的批准下颁发给客户端. 客户端使用访问令牌访问资源服务器托管的受保护资源.

在较旧, 更受限制的客户端-服务器身份验证模型中, 客户端通过使用资源所有者的凭据向服务器进行身份验证来请求服务器上的访问受限资源(受保护的资源). 为了向应用程序提供对受限资源的访问权限, 资源所有者与应用程序共享其凭据. 这会产生一些问题和限制:

  • 应用程序需要存储资源所有者的凭据以供将来使用, 这些的凭据通常是明文密码.
  • 服务器需要支持密码身份验证, 尽管密码中存在固有的安全漏洞.
  • 应用程序获得了对资源所有者的受保护资源的过于广泛的访问权限, 使资源所有者无法限制其访问的持续时间或对有限资源子集的访问权限.
  • 资源所有者经常在其他不相关的服务中重复使用密码. 密码重用意味着只要有一个服务出现漏洞或暴露, 就可能会在完全不相关的其他服务中产生安全隐患.
  • 资源所有者无法在不撤销对任何第三方的访问权限的情况下撤销对单个应用程序的访问权限, 并且必须通过更改其密码来实现.
  • 任何应用程序的泄露都会导致最终用户的密码以及受该密码保护的所有数据泄露.

使用 OAuth, 最终用户(资源所有者)可以授予打印服务(客户端)访问存储在照片共享服务(资源服务器)中的受保护照片的权限, 而无需与打印服务共享其用户名和密码. 相反, 它们直接使用照片共享服务(授权服务器)信任的服务器进行身份验证, 而该服务器则颁发给打印服务所需的特定凭据(访问令牌).

这种关注点分离的方式还提供了使用更高级的用户身份验证方法(如多重身份验证 MFA 甚至无密码身份验证)的能力, 而无需对应用程序进行任何修改. 由于所有用户身份验证逻辑都由授权服务器处理, 因此应用程序无需关注实现任何特定身份验证机制的细节. 这使授权服务器能够独立管理用户身份验证策略, 甚至可以在无需与应用程序协调的情况下更改它们.

授权层还可以简化资源服务器确定请求是否获得了授权的方式. 通常, 在对客户端进行身份验证后, 每个资源服务器都需要使用一点的策略判断客户端是否在每次 API 调用中都获得授权. 在分布式系统中, 这些策略需要同步到所有资源服务器, 或者资源服务器必须调用中央策略服务器来处理每个请求. 在 OAuth 中, 仅当授权服务器创建新的访问令牌时, 才会执行此类策略评估. 如果访问令牌中表示授权访问, 则资源服务器不再需要评估策略, 只需验证访问令牌.

OAuth 是授权协议, 不是身份验证协议. 访问令牌表示授予客户端的授权. 客户端通常将访问令牌提供给特定 API 来获取资源所有者的用户标识符, 然后将其结果用作对用户进行身份验证的一种方式. 但这种做法不是 OAuth 标准或安全注意事项的一部分, 同时资源所有者也可能未考虑到客户端的这种做法. 在采用这种做法之前, 实现者应仔细查阅资源服务器的文档.

此规范设计用于 HTTP ([RFC9110]) 协议. 在 HTTP 协议以外的任何协议上使用 OAuth 都超出此规范的范围.

自 2012 年 10 月发布 OAuth 2.0 授权框架 ([RFC6749]) 以来, 它已由适用于原生应用程序 (Native App) 的 OAuth 2.0 ([RFC8252]), OAuth 安全最佳实践当前实践 ([I-D.ietf-oauth-security-topics]) 和用于基于浏览器的应用程序的 OAuth 2.0 ([I-D.ietf-oauth-browser-based-apps]) 进行了更新. OAuth 2.0 授权框架: 持有者令牌用法 ([RFC6750]) 也已更新为 ([I-D.ietf-oauth-security-topics]). 此标准整合了所有这些文档中的信息, 并删除了在 [I-D.ietf-oauth-security-topics] 中发现不安全的功能.

# 1.1. 角色 Roles

OAuth 定义了四种角色:

  • "资源所有者" resource owner: 能够授予对受保护资源的访问权限的实体. 当资源所有者是人时, 它被称为最终用户. 有时缩写为"RO".
  • "资源服务器" resource server: 托管受保护资源的服务器, 能够使用访问令牌接受和响应受保护的资源请求. 通常可通过 API 访问资源服务器. 有时缩写为"RS".
  • "客户端" client: 代表资源所有者并经其授权发出受保护资源请求的应用程序. 术语 "客户端" 并不意味着任何特定的实现特征 (例如, 应用程序是在服务器, 桌面还是其他设备上执行).
  • "授权服务器" authorization server: 服务器在成功验证资源所有者并获取授权后向客户端颁发访问令牌. 有时缩写为"AS".

授权服务器和资源服务器之间的交互超出了此规范的范围, 但是本文定义多个扩展方式, 以提供资源服务器和授权服务器之间的互操作性选项. 授权服务器可以是与资源服务器相同的服务器, 也可以是单独的实体. 单个授权服务器可以颁发多个资源服务器接受的访问令牌.

# 1.2. 协议流程 Protocol Flow

     +--------+                               +---------------+
     |        |--(1)- Authorization Request ->|   Resource    |
     |        |                               |     Owner     |
     |        |<-(2)-- Authorization Grant ---|               |
     |        |                               +---------------+
     |        |
     |        |                               +---------------+
     |        |--(3)-- Authorization Grant -->| Authorization |
     | Client |                               |     Server    |
     |        |<-(4)----- Access Token -------|               |
     |        |                               +---------------+
     |        |
     |        |                               +---------------+
     |        |--(5)----- Access Token ------>|    Resource   |
     |        |                               |     Server    |
     |        |<-(6)--- Protected Resource ---|               |
     +--------+                               +---------------+

图 1: 抽象协议流程

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

  1. 客户端向资源所有者请求授权. 授权请求可以直接向资源所有者发出(如图所示), 或者最好通过授权服务器作为中介间接发出.
  2. 客户端接收授权授予, 该授权是表示资源所有者授权的凭据, 使用本规范中定义的授权类型之一或使用扩展授权类型表示. 授权类型取决于客户端用于请求授权的方法以及授权服务器支持的类型.
  3. 客户端通过向授权服务器进行身份验证并提供授权来请求访问令牌.
  4. 授权服务器对客户端进行身份验证并验证授权授予, 如果有效, 则颁发访问令牌.
  5. 客户端从资源服务器请求受保护的资源, 并通过提供访问令牌进行身份验证.
  6. 资源服务器验证访问令牌, 如果有效, 则为请求提供服务.

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

# 1.3. 授权授予 Authorization Grant

授权授予表示客户端用于获取访问令牌的资源所有者的授权 (访问其受保护的资源) 的方式.

此规范定义了三种授权类型 (授权代码 authorization code, 刷新令牌 refresh token 和客户端凭据 client credentials) 以及用于定义其他类型的扩展机制.

# 1.3.1. 授权码 Authorization Code

授权码是用于获取访问令牌的临时凭证. 客户端不是直接从资源所有者请求授权, 而是将资源所有者定向到授权服务器 (通过其用户代理, 而授权服务器又使用授权代码将资源所有者定向回客户端). 然后, 客户端就可以将授权代码交换为访问令牌.

在使用授权代码将资源所有者定向回客户端之前, 授权服务器会对资源所有者进行身份验证, 并可以请求资源所有者的同意或以其他方式通知他们客户端的请求. 由于资源所有者仅向授权服务器进行身份验证, 因此资源所有者的凭据永远不会与客户端共享, 并且客户端也不需要了解任何其他身份验证步骤, 例如多重身份验证或委派帐户.

授权代码提供了一些重要的安全优势, 例如能够对客户端进行身份验证, 以及将访问令牌直接传输到客户端, 而无需通过资源所有者的用户代理传递访问令牌, 或可能将其公开给其他人 (包括资源所有者).

# 1.3.2. 刷新令牌 Refresh Token

刷新令牌是用于获取访问令牌的凭据. 刷新令牌由授权服务器颁发给客户端, 用于在当前访问令牌无效或过期时获取新的访问令牌, 或者获取范围相同或更窄的其他访问令牌 (访问令牌的生存期可能比资源所有者授权的要短, 权限更少). 颁发刷新令牌是可选的, 由授权服务器自行决定, 可以根据客户端的属性, 请求的属性, 授权服务器中的策略或任何其他条件颁发刷新令牌. 如果授权服务器颁发刷新令牌, 则在颁发访问令牌时会包含刷新令牌 (即图 2 中的步骤 (2) ).

刷新令牌是一个字符串, 表示资源所有者授予客户端的授权. 该字符串对客户端不透明. 刷新令牌可以是用于检索授权信息的标识符, 也可以将此信息编码到字符串本身中. 与访问令牌不同, 刷新令牌仅用于授权服务器, 永远不会发送到资源服务器.

+--------+                                           +---------------+
|        |--(1)------- Authorization Grant --------->|               |
|        |                                           |               |
|        |<-(2)----------- Access Token -------------|               |
|        |               & Refresh Token             |               |
|        |                                           |               |
|        |                            +----------+   |               |
|        |--(3)---- Access Token ---->|          |   |               |
|        |                            |          |   |               |
|        |<-(4)- Protected Resource --| Resource |   | Authorization |
| Client |                            |  Server  |   |     Server    |
|        |--(5)---- Access Token ---->|          |   |               |
|        |                            |          |   |               |
|        |<-(6)- Invalid Token Error -|          |   |               |
|        |                            +----------+   |               |
|        |                                           |               |
|        |--(7)----------- Refresh Token ----------->|               |
|        |                                           |               |
|        |<-(8)----------- Access Token -------------|               |
+--------+           & Optional Refresh Token        +---------------+

图 2: 刷新过期的访问令牌

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

  1. 客户端通过向授权服务器进行身份验证并提供授权来请求访问令牌.
  2. 授权服务器对客户端进行身份验证并验证授权授予, 如果有效, 则颁发访问令牌和可选的刷新令牌.
  3. 客户端通过提供访问令牌向资源服务器发出受保护的资源请求.
  4. 资源服务器验证访问令牌, 如果有效, 则为请求提供服务.
  5. 重复步骤 (3) 和 (4), 直到访问令牌过期. 如果客户端知道访问令牌已过期, 则会跳到步骤 (7) ;否则, 它会发出另一个受保护的资源请求.
  6. 由于访问令牌无效, 资源服务器返回无效令牌错误.
  7. 客户端通过提供刷新令牌并提供客户端身份验证 (如果已颁发凭据) 来请求新的访问令牌. 客户端身份验证要求基于客户端类型和授权服务器策略.
  8. 授权服务器对客户端进行身份验证并验证刷新令牌, 如果有效, 则颁发新的访问令牌 (以及可选的新刷新令牌).

# 1.3.3. 客户凭证 Client Credentials

当授权范围仅限于客户端控制下的受保护资源或先前与授权服务器约定的受保护资源时, 客户端凭据或其他形式的客户端身份验证 (例如, 用于签署 JWT 的私钥, 如 [RFC7523] 中所述) 可用作授权授予. 当客户端根据先前与授权服务器约定的授权请求访问受保护资源时, 将使用客户端凭据而不是用户的访问令牌.

# 1.4. 访问令牌 Access Token

访问令牌是用于访问受保护资源的凭据. 访问令牌是一个字符串, 表示颁发给客户端的授权. 字符串对客户端来说是不透明的, 即使它有一个明确的结构. 根据授权服务器的不同, 资源服务器可以分析访问令牌字符串, 例如在使用访问令牌的 JSON Web 令牌配置文件 ([RFC9068] 时).

访问令牌表示由资源所有者授予并由资源服务器和授权服务器强制执行的特定访问范围和持续时间.

令牌可以由 RS 用于检索授权信息, 或者令牌可以以可验证的方式自包含授权信息 (即, 由签名数据有效负载组成的令牌字符串). 令牌检索机制的一个示例是令牌侦测 [RFC7662], 其中 RS 调用 AS 上的端点来验证客户端提供的令牌. 结构化令牌格式的一个示例是 [RFC9068], 这是一种将访问令牌数据编码为 JSON Web Token [RFC7519] 的方法.

客户端使用访问令牌时可能需要配合使用其他身份验证凭据 (超出此规范的范围). 这通常称为发件人约束的访问令牌 sender-constrained access token, 例如 DPoP [I-D.ietf-oauth-dpop] 和相互 TLS 访问令牌 [RFC8705].

访问令牌提供了一个抽象层, 将不同的授权结构 (例如, 用户名和密码) 替换为资源服务器可以理解的单个令牌. 这种抽象使得颁发访问令牌可以比以往获得访问令牌的方式更为严格, 并且使资源服务器无需了解各种身份验证方法.

根据资源服务器安全要求, 访问令牌可以具有不同的格式, 结构和利用方法 (例如, 加密属性). 访问令牌属性和用于访问受保护资源的方法可以扩展到本规范中所述的范围之外.

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

授权服务器必须确保未经授权的令牌无法生成, 修改或猜测访问令牌以生成有效的访问令牌.

# 1.5. 通讯安全 Communication security

框架实现者必须使用一种机制来提供通信身份验证, 完整性和机密性, 例如传输层安全性 [RFC8446], 以保护内容或标头字段中的明文凭据和令牌的交换免遭窃听, 篡改和消息伪造 (例如, 请参阅第 2.4.1 节, 第 7.6 节, 第 3.2 节和第 5.2 节).

OAuth 相关 URL 必须使用 HTTPS 协议, 但重定向到本机的 URI 除外, 后者可以使用 HTTP 协议. 使用 HTTPS 时, 必须根据 [RFC9110] 检查 TLS 证书. 在撰写本文时, TLS 的最新版本是 1.3 [RFC8446].

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

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

# 1.6. HTTP 重定向 HTTP Redirections

此规范广泛使用 HTTP 重定向, 其中客户端或授权服务器将资源所有者的用户代理定向到另一个目标. 虽然此规范中的示例显示了 HTTP 302 状态代码的使用, 但允许通过用户代理完成此重定向的任何其他方法 (HTTP 307 除外), 并被视为实现细节. 有关详细信息, 请参见第 7.5.2 节.

# 1.7. 互操作性 Interoperability

OAuth 2.1 提供了一个丰富的授权框架, 其中包含明确定义的安全属性.

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

  • [RFC8414]: 授权服务器元数据 Authorization Server Metadata, 定义客户端可用于查找与特定 OAuth 服务器交互所需的信息
  • [RFC7591]: 动态客户端注册 Dynamic Client Registration, 提供以编程方式向授权服务器注册客户端的机制
  • [RFC7592]: 动态客户端管理 Dynamic Client Management, 提供更新动态注册客户端信息的机制
  • [RFC7662]: 令牌侦测 Token Introspection, 为资源服务器定义一种机制, 以获取有关访问令牌的信息

请参阅附录 C, 了解本文发布时当前已知扩展的列表.

# 1.8. 与 OAuth 2.0 的兼容性 Compatibility with OAuth 2.0

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

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

# 1.9. 符号约定 Notational Conventions

本文档中的关键词"必须", "不得", "必需", "应", "不应", "应该", "不应", "推荐", "不推荐", "可以"和"可选"应按照 BCP 14 [RFC2119] [RFC8174] 中的说明进行解释, 如下所示.

此规范使用 [RFC5234] 的增强巴科斯-瑙尔形式 (ABNF) 表示法. 此外, 规则 URI 引用包含在"统一资源标识符 (URI) : 泛型语法"[RFC3986] 中.

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

术语"内容"应按照 [RFC9110] 第 6.4 节中所述进行解释.

术语"用户代理"应按照 [RFC9110] 第 3.5 节中所述进行解释.

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

# 2. 客户注册 Client Registration

在启动协议之前, 客户端必须向授权服务器进行注册. 客户端向授权服务器注册的方式超出了此规范的范围, 但通常涉及客户端开发人员在创建帐户并同意服务的服务条款后进行手动注册, 或使用动态客户端注册 ([RFC7591]) 在授权服务器的网站上自动注册客户端.

客户端注册不需要客户端和授权服务器之间的直接交互. 当授权服务器支持时, 注册可以依赖于其他方法来建立信任和获取所需的客户端属性 (例如, 重定向URI, 客户端类型). 例如, 可以使用自行颁发或第三方颁发的断言 assertion 完成注册, 也可以由授权服务器使用受信的方式道进行客户端发现 client discovery 完成注册.

注册客户端时, 客户端开发人员应:

  • 指定客户端类型, 如第 2.1 节中所述.
  • 提供正在使用的授权类型所需的客户端详细信息, 例如第 2.3 节中所述的重定向 URI.
  • 包括授权服务器要求的任何其他信息 (例如, 应用程序名称, 网站, 描述, 徽标图像, 法律条款的接受).

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

# 2.1. 客户类型 Client Types

OAuth 2.1 根据客户端类型向授权服务器安全进行身份验证的能力定义了两种客户端类型.

  • "机密的" confidential: 具有 AS 凭据的客户端被指定为"机密客户端"
  • "公共的" public: 没有凭据的客户端称为"公共客户端"

任何具有凭据的客户都必须采取预防措施, 以防止泄漏和滥用其凭据.

客户端身份验证允许授权服务器确保它与 OAuth 流程中的特定客户端 (由其 client_id 标识) 进行交互. 授权服务器可能会根据授权服务器与客户端通信的置信度, 对诸如是提示用户同意每次授权还是仅提示用户同意一次等事项做出策略决策.

授权服务器是否以及如何验证客户端或提供/操作此客户端的一方的身份超出了本规范的范围.

授权服务器在决定是否允许客户端访问更敏感的资源和操作 (如客户端凭据授权类型) 以及提示用户同意的频率时, 应考虑对客户端标识的置信度.

AS 不应将单个 client_id 视为多种类型的客户端.

此规范是围绕以下客户端类型设计的:

  • "网络应用程序" web application: Web 应用程序是在 Web 服务器上运行的客户端, 即运行在服务器上的服务型应用程序. 资源所有者通过资源所有者使用的设备上的用户代理中呈现的 HTML 用户界面访问客户端. 客户端凭据以及颁发给客户端的任何访问令牌存储在 Web 服务器上, 不会向资源所有者公开或由资源所有者访问.
  • "基于浏览器的应用程序" browser-based application: 基于浏览器的应用程序是从 Web 服务器下载客户端代码并在资源所有者使用的设备上的用户代理 (例如 Web 浏览器) 内执行的客户端. 协议数据和凭据对资源所有者来说很容易访问 (并且通常可见). 如果希望此类应用程序使用客户端凭据, 建议使用后端用于前端模式 backend for frontend. 由于此类应用程序驻留在用户代理中, 因此它们可以在请求授权时无缝使用用户代理功能.
  • "原生应用程序" native application: 原生应用程序是在资源所有者使用的设备上安装和执行的客户端. 资源所有者可以访问协议数据和凭据. 通常假定应用程序中包含的任何客户端身份验证凭据都有可能被提取. 动态颁发的访问令牌和刷新令牌可以获得可接受的保护级别. 在某些平台上, 这些凭据受到保护, 不受驻留在同一设备上的其他应用程序的影响. 如果此类应用程序希望使用客户端凭据, 建议使用后端用于前端模式, 或在运行时使用动态客户端注册 ([RFC7591]) 颁发凭据.

# 2.2. 客户端标识符 Client Identifier

在授权服务器的上下文中, 每个客户端都由客户端标识符进行标识, 客户端标识符是表示客户端提供的注册信息的唯一字符串. 虽然授权服务器通常自己颁发客户端标识符, 但它也可能为其他授权服务器创建的客户端提供服务. 客户端标识符不是机密. 它向资源所有者公开, 不得单独用于客户端身份验证. 客户端标识符在授权服务器的上下文中是唯一的.

此规范未定义客户端标识符字符串大小. 客户端应避免对标识符大小做出假设. 授权服务器应记录它颁发的任何标识符的大小.

如果授权服务器支持具有由授权服务器以外的各方颁发的客户端标识符的客户端, 则授权服务器应采取预防措施, 以避免客户端模拟资源所有者, 如第 7.4 节所述.

# 2.3. 客户端重定向端点 Client Redirection Endpoint

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

授权服务器将用户代理重定向到客户端注册过程中与授权服务器约定的重定向端点之一.

重定向 URI 必须是 [RFC3986] 第 4.3 节定义的绝对 URI. 重定向 URI 可能包括 application/x-www-form-urlencoded 格式的查询组件 ([WHATWG.URL]), 在添加其他查询参数时必须保留该参数. 重定向 URI 不得包含片段组件.

# 2.3.1. 注册要求 Registration Requirements

授权服务器必须要求客户端注册其完整的重定向 URI (包括路径组件). 授权服务器必须拒绝指定与已注册的 URI 不完全匹配的重定向 URI 的授权请求, 环回 loopback 重定向除外. 其中需要除端口 URI 组件之外的完全匹配, 有关详细信息, 请参阅第 4.1.1 节.

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

客户端注册既可能发生在带外 out of band, 例如在授权服务器上手动配置客户端信息, 也可能在运行时发生, 例如在推送授权请求 [RFC9126] 中的初始 POST 中.

对于私有使用的基于 URI 协议的重定向 URI, 授权服务器应强制执行第 8.4.3 节中的要求, 即客户端使用基于逆序域名的 URI 协议. 至少不包含句点字符 (.) 的任何专用 URI 应该被拒绝.

除了防冲突属性之外, 这还有助于在发生争议时证明所有权, 即两个应用声明相同的专用 URI (其中一个应用存在恶意行为). 例如, 如果两个应用都声称 com.example.app 是自己的专用 URI, 那么 example.com 所有者就可以请求应用商店运营商删除假冒应用.

由于开放式重定向器 open redirector 可能使授权代码和访问令牌遭到泄露, 因此客户端不得公开将用户浏览器转发到从查询参数获得的任意 URI 的 URL. 相关信息请参阅第 7.13 节所述.

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

如果无需注册重定向 URI, 那么攻击者即可将授权端点用作开放重定向器, 如第 7.13 节中所述.

# 2.3.2. 多个重定向 URI Multiple Redirect URIs

如果已注册多个重定向 URI, 则客户端必须使用 redirect_uri 请求参数在授权请求中指定本次请求的重定向 URI.

# 2.3.3. 防止 CSRF 攻击 Preventing CSRF Attacks

客户端必须防止跨站点请求伪造 (CSRF) 攻击. 在此上下文中, CSRF 是指对重定向端点的请求, 这些请求不是源自授权服务器, 而是恶意第三方 (有关详细信息, 请参阅 [RFC6819] 的第 4.4.1.8 节). 确保授权服务器支持 code_challenge 参数的客户端可以依赖该机制提供的 CSRF 保护. 在 OpenID Connect 流程中, 验证随机数参数可提供 CSRF 保护. 否则, 必须在状态参数中携带的一次性 CSRF 令牌, 并将这些令牌安全地绑定到用户代理, 用于 CSRF 保护 (参见第 7.10 节).

# 2.3.4. 防止混淆攻击 Preventing Mix-Up Attacks

为了防止混淆攻击, 客户端必须仅处理它们向其发起此授权请求的授权服务器的重定向响应. 客户端必须存储它们向其发送授权请求的授权服务器, 并将此信息绑定到用户代理, 并检查是否从正确的授权服务器收到授权响应. 客户端必须确保将后续访问令牌请求 (如果适用) 发送到同一授权服务器. 客户端应为每个授权服务器使用不同的重定向 URI, 作为标识特定响应来自的授权服务器的方法.

# 2.3.5. 无效端点 Invalid Endpoint

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

# 2.3.6. 端点内容 Endpoint Content

对客户端端点的重定向请求通常会导致用户代理显示一个 HTML 文档. 如果此 HTML 响应直接作为重定向请求的结果, 则 HTML 文档中包含的任何脚本都将以对重定向 URI 及其包含的项目 (例如授权代码) 的完全访问权限执行. 此外, 包含授权代码的请求 URL 可以在 HTTP Referer 标头中发送到页面中加载的任何嵌入式图像, 样式表和其他元素.

客户端不应在重定向 URI 端点响应中包含任何第三方脚本 (例如, 第三方分析, 社交插件, 广告网络). 相反, 它应该从 URI 中提取出这些工件 artifact, 并将用户代理再次重定向到另一个端点, 从而避免公开这些工件 (在 URI 或其他位置). 如果包含第三方脚本, 则客户端必须确保其自己的脚本 (用于从 URI 中提取和删除凭据) 将首先执行.

# 2.4. 客户端认证 Client Authentication

授权服务器必须仅当基础凭据的颁发/注册和分发过程都能确保其机密性时, 才依赖客户端身份验证.

如果客户端是机密的, 授权服务器可以接受满足其安全要求的任何形式的客户端身份验证 (例如, 密码, 公钥/私钥对).

建议使用非对称 (基于公钥) 方法进行客户端身份验证, 例如 mTLS [RFC8705] 或根据 [RFC7521] 和 [RFC7523] (在 [OpenID] 中定义为客户端身份验证方法 private_key_jwt) 使用签名的 JWT ("私钥 JWT"). 使用此类客户端身份验证方法时, 授权服务器不需要存储敏感的对称密钥, 从而使这些方法更可靠地抵御许多攻击.

当无法进行客户端身份验证时, 授权服务器应采用其他方法来验证客户端的标识, 例如, 要求注册客户端重定向 URI 或登记资源所有者以确认身份. 有效的重定向 URI 不足以在请求资源所有者授权时验证客户端的身份, 但可用于防止在获取资源所有者授权后将凭据传递给伪造客户端.

客户端不得在每个请求中使用多个身份验证方法, 以防止服务端身份验证机制对请求的权威性发生冲突.

授权服务器必须考虑与未经身份验证的客户端交互的安全隐患, 并采取措施限制颁发给此类客户端的令牌 (例如, 限制刷新令牌的生存期).

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

# 2.4.1. 客户秘密 Client Secret

拥有客户端密码 client secert (有时称为客户端密码 client password) 的客户端可以使用 [RFC9110] 第 11 节中定义的 HTTP 基本身份验证方案向授权服务器进行身份验证. 客户端标识符使用附录 B 中的 application/x-www-form-urlencoding 编码算法进行编码, 并将编码值用作用户名, 同时将客户端密码使用相同的算法进行编码, 并用作密码. 授权服务器必须支持 HTTP 基本身份验证方案, 以便对已颁发客户端密码的客户端进行身份验证.

例如 (带有额外的换行符仅用于显示目的) :

Authorization:  Basic czZCaGRSa3F0Mzo3RmpmcDBaQnIxS3REUmJuZlZkbUl3

除此之外, 授权服务器可能支持使用以下参数在请求内容中包含客户端凭据:

  • "client_id": 必填. 在第 2.2 节所述的注册过程中发给客户端的客户端标识符.
  • "client_secret": 必填. 客户端密码.

不建议在请求内容中使用这两个参数传递客户端凭据, 并且应仅限于无法直接使用 HTTP 基本身份验证方案 (或其他基于密码的 HTTP 身份验证方案) 的客户端.参数只能在请求内容中传输, 不得包含在请求 URI 中.

例如, 使用请求体中的内容参数刷新访问令牌的请求 (第 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

由于此客户端身份验证方法涉及密码, 因此授权服务器必须保护使用它的任何端点免受暴力攻击.

# 2.4.2. 其他认证方法 Other Authentication Methods

授权服务器可以支持符合其安全要求的任何合适的身份验证方案. 使用其他身份验证方法时, 授权服务器必须定义客户端标识符和身份验证方案之间的映射.

你可以在在 "OAuth 令牌端点身份验证方法" 注册表中找到一些其他身份验证方法 (如 mTLS [RFC8705] 和私钥 JWT [RFC7523] ) 的定义. 除了保护令牌端点的特定用途之外, 这些方法可能用作通用客户端身份验证方法.

# 2.5. 未注册客户 Unregistered Clients

此规范不要求向授权服务器注册客户端. 但是, 使用未注册的客户端超出了此规范的范围, 需要额外的安全分析和审查其互操作性影响.

# 3. 协议端点 Protocol Endpoints

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

  • 授权端点 Authorization endpoint - 客户端用于通过用户代理重定向从资源所有者获取授权.
  • 令牌端点 Token endpoint - 客户端用于交换访问令牌的授权授予, 通常使用客户端身份验证.

以及一个客户端端点:

  • 重定向端点 Redirection endpoint - 授权服务器用于通过资源所有者的用户代理将包含授权凭据的响应返回到客户端. 并非每个授权授权类型都使用这两个端点. 扩展授权类型可以根据需要定义其他端点.

# 3.1. 授权端点 Authorization Endpoint

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

客户端获取授权端点 URL 的方法超出了此规范的范围, 但 URL 通常在服务文档或授权服务器的元数据文档 ([RFC8414]) 中提供.

授权端点 URL 不得包含片段组件, 并且可以包含 application/x-www-form-urlencoded 格式的查询组件 [WHATWG.URL], 并且在添加其他查询参数时必须保留该参数.

授权服务器必须支持对授权端点使用 [RFC9110] 中第 9.3.1 节介绍的 HTTP GET 方法, 并且还可以支持 [RFC9110] 的第 9.3.3 节中介绍的 POST 方法.

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

此规范定义的请求和响应参数不得在同一个请求/响应中多次出现. 客户端发送的不带值的参数必须被视为从请求中省略了它们.

重定向可能包含用户凭据的请求的授权服务器必须避免意外转发这些用户凭据 (有关详细信息, 请参见第 7.5.2 节).

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

# 3.2. 令牌端点 Token Endpoint

客户端通过授权授予的方式 (如第 4 节和第 4.3 节中所述的授权) 使用令牌端点获取访问令牌.

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

令牌端点 URL 不得包含片段组件, 并且可以包含 application/x-www-form-urlencoding 格式查询组件 ([WHATWG.URL]).

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

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

此规范定义的请求和响应参数不得在同一个请求/响应中多次出现. 客户端发送的不带值的参数必须被视为从请求中省略了它们.

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

# 3.2.1. 客户端认证 Client Authentication

机密客户端必须按照第 2.4 节中所述向令牌端点发出请求时向授权服务器进行身份验证.

客户端身份验证用于:

  • 强制将刷新令牌和授权代码 authorization code 绑定到颁发它们的客户端. 当授权代码通过不安全的通道传输到重定向端点时, 客户端身份验证增加了额外的安全层.
  • 通过禁用客户端或更改其凭据而使受损客户端得以恢复, 从而防止攻击者滥用被盗的刷新令牌. 更改一组客户端凭据比撤销整组刷新令牌要快得多.
  • 实施身份验证管理最佳做法, 这需要定期进行凭据轮换. 轮换整组刷新令牌可能具有挑战性, 而轮换一组客户端凭据要容易得多.

# 3.2.2. 令牌请求 Token Request

客户端通过根据附录 B 使用 application/x-www-form-urlencoding 格式发送以下参数, 并在 HTTP 请求内容中使用 UTF-8 字符编码, 向令牌端点发出请求:

  • "client_id": 必需, 如果客户端未按照第 3.2.1 节所述向授权服务器进行身份验证.
  • "grant_type": 必填. 客户端用于特定令牌请求的授权类型的标识符. 此规范定义值 authorization_code, refresh_tokenclient_credentials.

授权类型 grant_type 决定着令牌请求需要的参数, 你可以在本文的下述章节查看这些授权类型的详细信息定义.

机密客户端必须按照第 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=authorization_code&code=SplxlOBeZQQYbYS6WxSbIA
&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb
&code_verifier=3641a2d12d66101249cdf7a79c000c1f8c05d2aafcf14bf146497bed

授权服务器必须:

  • 要求对机密客户端 (或具有其他身份验证要求的客户端) 进行客户端身份验证,
  • 如果包括客户端身份验证, 则对客户端进行身份验证.

然后再适用使用相应的授权类型进行校验和处理.

# 3.2.2.1. 访问令牌范围 Access Token Scope

授权和令牌端点允许客户端使用 scope 请求参数指定访问请求的范围. 反过来, 授权服务器使用 scope 响应参数通知客户端所颁发的访问令牌的范围.

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

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

授权服务器可以根据授权服务器策略或资源所有者的要求忽略全部或部分客户端请求的范围. 如果颁发的访问令牌范围与客户端请求的范围不同, 则授权服务器必须在令牌响应中包含范围响应参数 (第 3.2.3 节), 以通知客户端授予的实际范围.

如果客户端在请求授权时省略了 scope 参数, 则授权服务器必须使用预定义的默认值处理请求, 或者认为无效的请求范围. 授权服务器应记录其作用域要求和默认值 (如果定义了默认值的话).

# 3.2.3. 令牌响应 Token Response

如果访问令牌请求有效且已授权, 则授权服务器将颁发访问令牌和可选的刷新令牌.

如果请求客户端身份验证失败或无效, 授权服务器将返回错误响应, 如第 3.2.3.1 节中所述.

授权服务器通过使用 [RFC8259] 定义的 application/json 媒体类型创建 HTTP 响应内容, 并使用以下参数和 HTTP 200 (正常) 状态代码, 从而颁发访问令牌和可选的刷新令牌:

  • "access_token": 必填. 授权服务器颁发的访问令牌.
  • "token_type": 必填. 第 5.1 节中所述的颁发的访问令牌的类型. 值不区分大小写.
  • "expires_in": 推荐. 访问令牌的生存期 (以秒为单位). 例如, 值 3600 表示访问令牌将在生成响应后的一小时内过期. 如果省略, 授权服务器应通过其他方式提供过期时间或记录默认值.
  • "scope": 如果与客户请求的范围相同, 则推荐;否则, 为必填项. 访问令牌的范围, 如第 3.2.2.1 节所述.
  • "refresh_token": 可选. 刷新令牌, 可用于根据相应令牌请求中传递的授权获取新的访问令牌.

授权服务器应根据风险评估和自己的策略确定是否向特定客户端颁发刷新令牌. 如果授权服务器决定不颁发刷新令牌, 则客户端可以通过启动 OAuth 流程 (例如启动新的授权代码请求) 来获取新的访问令牌. 在这种情况下, 授权服务器可以利用 cookie 和持久授权来优化用户体验.

如果颁发了刷新令牌, 则这些刷新令牌必须绑定到资源所有者同意的范围和资源服务器. 这是为了防止合法客户端提升权限, 并减少刷新令牌泄漏的影响.

参数被序列化为 JavaScript 对象表示法 (JSON) 结构中的最高结构级别参数. 参数名称和字符串值作为 JSON 字符串包含在内. 数值以 JSON 数字的形式包含在内. 参数的顺序无关紧要, 可以变化.

授权服务器必须在包含令牌, 凭据或其他敏感信息的任何响应中包含 HTTP 缓存控制响应标头字段 (请参阅 [RFC9111] 的第 5.2 节), 其值为 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"
}

客户端必须忽略响应中无法识别的值名称. 客户端应避免对授权服务器返回的令牌或其他值的大小做出假设, 但授权服务器应记录它发出的任何值的大小.

# 3.2.3.1. 错误响应 Error Response

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

  • "error": 必填. 来自以下的单个 ASCII [USASCII] 错误代码: 错误参数的值不得包含集合 %x20-21 / %x23-5B / %x5D-7E 之外的字符.
    • "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_description": 可选. 人类可读的 ASCII [USASCII] 文本提供附加信息, 用于帮助客户端开发人员了解发生的错误. error_description参数的值不得包含集合 %x20-21 / %x23-5B / %x5D-7E 之外的字符.
  • "error_uri": 可选. 一个 URI, 用于标识包含有关错误信息的人类可读网页, 用于向客户端开发人员提供有关错误的其他信息. error_uri 参数的值必须符合 URI 引用语法, 因此不得包含集合 %x21 / %x23-5B / %x5D-7E 之外的字符.

这些参数使用 [RFC7159] 定义的 application/json 媒体类型包含在 HTTP 响应的内容中. 参数被序列化为 JavaScript 对象表示法 (JSON) 结构中的最高结构级别参数. 参数名称和字符串值作为 JSON 字符串包含在内. 数值以 JSON 数字的形式包含在内. 参数的顺序无关紧要, 可以变化.

例如:

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

{
 "error":"invalid_request"
}

# 4. 授权类型 Grant Types

若要请求访问令牌, 客户端需要从资源所有者处获取授权. 此规范定义了以下授权类型:

  • 授权码 authorization code
  • 客户端凭据 client credentials
  • 刷新令牌 refresh token

同时此规范还提供了用于定义其他授权类型的扩展机制.

# 4.1. 授权码授予 Authorization Code Grant

授权代码授予类型用于获取访问令牌和刷新令牌.

授权类型使用附加授权端点让授权服务器与资源所有者交互, 以获取资源访问的同意 consent.

由于这是基于重定向的流程, 因此客户端必须使用资源所有者的用户代理 (通常是 Web 浏览器) 启动流程, 并且从授权服务器重定向回流.

 +----------+
 | Resource |
 |   Owner  |
 +----------+
       ^
       |
       |
 +-----|----+          Client Identifier      +---------------+
 | .---+---------(1)-- & Redirect URI ------->|               |
 | |   |    |                                 |               |
 | |   '---------(2)-- User authenticates --->|               |
 | | User-  |                                 | Authorization |
 | | Agent  |                                 |     Server    |
 | |        |                                 |               |
 | |    .--------(3)-- Authorization Code ---<|               |
 +-|----|---+                                 +---------------+
   |    |                                         ^      v
   |    |                                         |      |
   ^    v                                         |      |
 +---------+                                      |      |
 |         |>---(4)-- Authorization Code ---------'      |
 |  Client |          & Redirect URI                     |
 |         |                                             |
 |         |<---(5)----- Access Token -------------------'
 +---------+      (w/ Optional Refresh Token)

图 3: 授权代码流程

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

  1. 客户端通过将资源所有者的用户代理定向到授权端点来启动流程. 客户端包括其客户端标识符 client id, 代码质询 code challenge (派生自生成的代码验证程序), 可选的请求范围 scope, 可选的本地状态 state 以及重定向 URI redirect uri, 一旦授予 (或拒绝) 访问权限, 授权服务器将用户代理发送回该 URI.
  2. 授权服务器 (通过用户代理) 对资源所有者进行身份验证, 并确定资源所有者是允许还是拒绝客户端的访问请求.
  3. 假设资源所有者授予访问权限, 授权服务器将使用之前提供的重定向 URI (在请求中或客户端注册期间) 将用户代理重定向回客户端. 重定向 URI 包括客户端之前提供的授权代码 authorization code 和任何本地状态 state.
  4. 客户端通过传递上一步中收到的授权代码 authorization code 以及其代码验证程序 code_verifier, 从授权服务器的令牌端点请求访问令牌. 发出请求时, 客户端会向授权服务器进行身份验证 (如果可以), 同时传递用于获取验证授权代码的重定向 URI.
  5. 授权服务器尽可能对客户端进行身份验证, 验证授权代码, 验证代码验证程序, 并确保收到的重定向 URI 与步骤 3 中用于重定向客户端的 URI 匹配. 如果有效, 授权服务器将使用访问令牌和刷新令牌 (可选) 进行响应.

# 4.1.1. 授权请求 Authorization Request

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

客户端为每个授权请求使用唯一的密钥来防止授权代码注入和 CSRF 攻击. 客户端首先生成此密钥, 它可以在兑换授权代码时使用该密钥来证明使用该授权代码的客户端是请求它的同一客户端.

客户端通过使用 application/x-www-form-urlencoding 格式将以下参数添加到授权端点 URI 的查询组件来构造请求 URI, 具体取决于附录 B:

  • “response_type”: 必填. 授权端点支持不同的请求和响应参数集. 客户端使用特定的 response_type 值确定流程的类型. 此规范定义值 code, 必须使用该值代码来指示客户端想要使用授权代码流程.

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

某些扩展响应类型由 ([OpenID]) 定义.

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

  • “client_id”: 必填. 第 2.2 节中所述的客户端标识符.
  • “code_challenge”: 必需或推荐 (请参阅第 7.6 节). 代码挑战.
  • “code_challenge_method”: 可选, 如果请求中不存在, 则默认为纯文本. 代码验证器转换方法是 S256 或普通.
  • “redirect_uri”: 可选. 如第 2.3 节所述.
  • “scope”: 可选. 访问请求的范围, 如第 3.2.2.1 节所述.
  • “state”: 可选. 客户端用于维护请求和回调之间的状态的不透明值. 授权服务器在将用户代理重定向回客户端时包含此值.

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 的代码质询方法 code challenge. 否则, 可以读取授权请求的攻击者 (参见 [I-D.ietf-oauth-security-topics] 中的攻击者 A4) 可以破坏此机制提供的安全性. 目前, S256 是唯一可行的方法.

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

然后, 客户端通过在代码验证程序上使用以下转换之一创建从代码验证程序派生的 code_challenge:

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

plain
  code_challenge = code_verifier

如果客户端能够使用 S256, 则必须使用 S256, 因为 S256 是服务器上强制实现 (MTI). 仅当客户端由于某些技术原因而无法支持 S256 时, 才允许客户端使用 plain, 例如没有可用的哈希函数的受限环境, 并且通过带外配置或通过授权服务器元数据 ([RFC8414]) 知道服务器支持纯文本.

code_challenge 的 ABNF 如下:

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

属性 code_challengecode_verifier 采用自 OAuth 2.0 扩展, 称为 “代码交换的证明密钥” 或 PKCE ([RFC7636]), 该技术最初是在其中开发的.

授权服务器必须支持 code_challengecode_verifier 参数.

客户端必须使用 code_challengecode_verifier, 授权服务器必须强制使用, 除非在第 7.6 节中描述的条件. 在这种情况下, 仍建议使用和强制执行如下所述的 code_challengecode_verifier.

状态 state 和范围 scope 参数不应包含纯文本形式的敏感客户端或资源所有者信息, 因为它们可以通过不安全的通道传输或不安全存储.

客户端使用 HTTP 重定向或通过用户代理提供的其他方式将资源所有者定向到构造的 URI.

例如, 客户端指示用户代理发出以下 HTTP 请求 (带有额外的换行符仅用于显示目的) :

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 相等, 有关详细信息, 请参见 [RFC3986] 第 6.2.1 节, 简单字符串比较.

如果请求有效, 授权服务器将对资源所有者进行身份验证并获取授权决策 (通过询问资源所有者或通过其他方式建立共识).

建立决策后, 授权服务器使用 HTTP 重定向响应或通过用户代理提供的其他方式将用户代理定向到提供的客户端重定向 URI.

# 4.1.2. 授权响应 Authorization Response

如果资源所有者授予访问请求, 则授权服务器会根据附录 B 使用 application/x-www-form-urlencoding 格式将以下参数添加到重定向 URI 的查询组件, 从而发出授权代码并将其传递给客户端:

  • “code”: 必填. 授权代码由授权服务器生成, 对客户端不透明. 授权代码必须在发布后不久过期, 以降低泄漏风险. 建议授权代码的最长生存期为 10 分钟. 客户端不得多次使用授权代码. 如果多次使用授权代码, 则授权服务器必须拒绝该请求, 并应 (如果可能) 撤销之前基于该授权代码颁发的所有访问令牌和刷新令牌. 授权代码绑定到客户端标识符, 代码质询和重定向 URI.
  • “state”: 如果客户端授权请求中存在状态参数, 则为必需. 从客户端收到的确切值.
  • “iss”: 可选. 授权服务器的标识符, 如果客户端与多个授权服务器交互, 客户端可以使用该标识符来防止混淆攻击. 有关何时需要此参数以及客户端如何使用它来防止混淆攻击的其他详细信息, 请参阅 [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

客户端必须忽略无法识别的响应参数. 此规范未定义授权代码字符串大小. 客户端应避免对代码值大小做出假设. 授权服务器应记录它发出的任何值的大小.

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

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

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

# 4.1.2.1. 错误响应 Error Response

如果请求由于重定向 URI 缺失, 无效或不匹配而失败, 或者客户端标识符丢失或无效, 则授权服务器应将错误通知资源所有者, 并且不得自动将用户代理重定向到无效的重定向 URI.

AS 必须在没有来自公共客户端 code_challenge 的情况下拒绝请求, 并且必须拒绝来自其他客户端的此类请求, 除非有合理的保证客户端以其他方式缓解授权代码注入. 有关详细信息, 请参阅第 7.6 节.

如果服务器不支持请求的 code_challenge_method 转换, 则授权端点必须返回错误值设置为 invalid_request 的授权错误响应. error_urierror_description 或响应应该解释错误的性质, 例如, 不支持转换算法.

如果资源所有者拒绝访问请求, 或者请求由于重定向 URI 缺失或无效以外的原因而失败, 则授权服务器会根据附录 B 使用 application/x-www-form-urlencoding 格式将以下参数添加到重定向 URI 的查询组件中通知客户端:

  • “error”: 必填. 来自以下的单个 ASCII [USASCII] 错误代码: 错误参数的值不得包含集合 %x20-21 / %x23-5B / %x5D-7E 之外的字符.
    • “invalid_request”: 请求缺少必需参数, 包含无效的参数值, 多次包含参数或格式不正确.
    • “unauthorized_client”: 客户端无权使用此方法请求授权代码.
    • “access_denied”: 资源所有者或授权服务器拒绝了请求.
    • “unsupported_response_type”: 授权服务器不支持使用此方法获取授权码.
    • “invalid_scope”: 请求的范围无效, 未知或格式不正确.
    • “server_error”: 授权服务器遇到意外情况, 阻止它完成请求. (此错误代码是必要的, 因为无法通过 HTTP 重定向将 500 内部服务器错误 HTTP 状态代码返回到客户端.
    • “temporarily_unavailable”: 由于服务器的临时过载或维护, 授权服务器当前无法处理请求. (此错误代码是必要的, 因为无法通过 HTTP 重定向将 503 服务不可用 HTTP 状态代码返回到客户端).
  • “error_description”: 可选. 人类可读的 ASCII [USASCII] 文本提供附加信息, 用于帮助客户端开发人员了解发生的错误. error_description 参数的值不得包含集合 %x20-21 / %x23-5B / %x5D-7E 之外的字符.
  • “error_uri”: 可选. 一个 URI, 用于标识包含有关错误信息的人类可读网页, 用于向客户端开发人员提供有关错误的其他信息. error_uri 参数的值必须符合 URI 引用语法, 因此不得包含集合 %x21 / %x23-5B / %x5D-7E 之外的字符.
  • “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. 令牌端点扩展 Token Endpoint Extension

此授权的授权类型在令牌端点上通过 grant_type 值为 authorization_code 进行标识.

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

  • “code”: 必填. 从授权服务器接收的授权代码.
  • “code_verifier”: 当授权请求中包含 code_challenge 参数时必填. 不得以其他方式使用. 原始代码验证程序字符串.

例如, 客户端发出以下 HTTP 请求 (带有额外的换行符仅用于显示目的) :

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. 客户凭证授予 Client Credentials Grant

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

客户端凭据授予类型只能由机密客户端使用.

     +---------+                                  +---------------+
     |         |                                  |               |
     |         |>--(1)- Client Authentication --->| Authorization |
     | Client  |                                  |     Server    |
     |         |<--(2)---- Access Token ---------<|               |
     |         |                                  |               |
     +---------+                                  +---------------+

图 4: 客户凭证授予

图 4 中所示的客户端凭据授予的使用包括以下步骤:

  1. 客户端向授权服务器进行身份验证, 并从令牌端点请求访问令牌.
  2. 授权服务器对客户端进行身份验证, 如果有效, 则颁发访问令牌.

# 4.2.1. 令牌端点扩展 Token Endpoint Extension

此授权的授权类型在令牌端点上通过 grant_type 值为 client_credentials 进行标识.

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

  • “scope”: 可选. 访问请求的范围, 如第 3.2.2.1 节所述.

例如, 客户端使用 LTS 发出以下 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. 刷新令牌授予 Refresh Token Grant

刷新令牌是授权服务器颁发给客户端的凭据, 可用于基于现有授权获取新的访问令牌. 客户端使用此选项是因为以前的访问令牌已过期, 或者客户端以前获取的访问令牌的范围比相应授权批准的范围更窄, 后来需要同一授权下具有不同范围的访问令牌.

刷新令牌在传输和存储过程中必须保密, 并且仅在授权服务器和向其颁发刷新令牌的客户端之间共享. 授权服务器必须维护刷新令牌与向其颁发刷新令牌的客户端之间的绑定.

只要可以对客户端标识进行身份验证, 授权服务器就必须验证刷新令牌和客户端标识之间的绑定. 当客户端身份验证不可行时, 授权服务器应发出受发送方约束的刷新令牌或使用刷新令牌轮换, 如第 4.3.1 节中所述.

授权服务器必须确保未经授权的各方无法生成, 修改或猜测刷新令牌以生成有效的刷新令牌.

# 4.3.1. 令牌端点扩展 Token Endpoint Extension

此授权的授权类型在令牌端点上通过 grant_type 值为 refresh_token 进行标识.

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

  • “refresh_token”: 必填. 颁发给客户端的刷新令牌.
  • “scope”: 可选. 访问请求的范围, 如第 3.2.2.1 节所述. 请求的范围不得包括最初未由资源所有者授予的任何范围, 如果省略, 则被视为等于资源所有者最初授予的范围.

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

例如, 客户端使用 TLS 发出以下 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,
  • 请确保已将刷新令牌颁发给匹配的客户端
  • 验证与此刷新令牌对应的授权是否仍处于活动状态
  • 验证刷新令牌

授权服务器必须利用以下方法之一来检测公共客户端的恶意参与者的刷新令牌重播攻击:

  • 发送方约束的刷新令牌: 授权服务器以加密方式将刷新令牌绑定到某个客户端实例, 例如通过使用 [RFC8705] 或 [I-D.ietf-oauth-dpop].
  • 刷新令牌轮换: 授权服务器为每个访问令牌刷新响应颁发新的刷新令牌. 以前的刷新令牌无效, 但有关关系的信息由授权服务器保留. 如果刷新令牌遭到入侵并随后被攻击者和合法客户端使用, 则其中一个客户端将提供无效的刷新令牌, 该令牌将通知授权服务器违规行为. 授权服务器无法确定哪一方提交了无效的刷新令牌, 但它将撤销活动的刷新令牌以及与之关联的访问授权. 这会以强制合法客户端获得新的授权为代价来阻止攻击.

实现者需要注意: 刷新令牌所属的授权可以编码到刷新令牌本身中. 这使授权服务器能够有效地确定刷新令牌所属的授权, 并扩展确定需要吊销的所有刷新令牌. 在这种情况下, 授权服务器必须确保刷新令牌值的完整性, 例如, 使用签名.

# 4.3.2. 刷新令牌响应 Refresh Token Response

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

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

# 4.3.3. 刷新令牌时的推荐措施 Refresh Token Recommendations

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

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

  • 密码更改
  • 在授权服务器上注销

如果客户端处于非活动状态一段时间, 即刷新令牌在一段时间内未用于获取新的访问令牌, 则刷新令牌应过期. 过期时间由授权服务器自行决定. 它可以是全局值, 也可以根据客户端策略或与刷新令牌关联的授权 (及其敏感度) 确定.

# 4.4. 扩展授予方式 Extension Grants

客户端使用扩展授权类型, 方法是使用绝对 URI (由授权服务器定义) 指定授权类型作为令牌端点的 grant_type 参数的值, 并添加任何其他必要的参数.

例如, 要在用户在单独的设备上授权客户端, 使用 [RFC8628] 定义的设备授权授予请求访问令牌, 客户端将发出以下 HTTP 请求 ( 带有额外的换行符仅用于显示目的) :

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.3.1 节中所述.

# 5. 访问受保护的资源 Accessing Protected Resources

客户端通过向资源服务器提供访问令牌来访问受保护的资源. 资源服务器必须验证访问令牌, 并确保它未过期, 并且其范围涵盖请求的资源.

资源服务器用于验证访问令牌 (以及任何错误响应) 的方法超出了此规范的范围, 但通常涉及资源服务器和授权服务器之间的交互或协调. 例如, 当资源服务器和授权服务器位于同一位置或属于同一系统时, 它们可以共享数据库或其他存储;当这两个组件独立运行时, 它们可以使用令牌侦测 [RFC7662] 或结构化访问令牌格式, 例如 JWT [RFC9068].

客户端利用访问令牌访问资源服务器上受保护资源的方法取决于授权服务器颁发的访问令牌的类型. 通常, 它涉及将 HTTP 授权请求标头字段 [RFC7235] 与由所用访问令牌类型的规范定义的身份验证方案一起使用, 例如下面定义的不记名/持有者令牌.

# 5.1. 访问令牌类型 Access Token Types

访问令牌类型为客户端提供成功利用访问令牌发出受保护资源请求所需的信息 (以及特定于类型的属性). 如果客户端不了解令牌类型, 则不得使用访问令牌.

例如, 此规范中定义的持有者令牌类型只需在请求中包含访问令牌字符串即可使用:

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

以上示例仅用于说明目的.

每个访问令牌类型定义了发送到客户端的可选的其他属性以及 access_token 响应参数. 它还定义了用于在发出受保护资源请求时包含访问令牌的 HTTP 身份验证方法.

# 5.2. 不记名/持有者令牌 Bearer Tokens

不记名令牌是一种安全令牌, 其属性是拥有令牌的任何一方 (“持有者”) 都可以以任何其他拥有令牌的方式使用该令牌. 使用持有者令牌不需要持有者证明拥有加密密钥材料 (所有权证明).

不记名令牌可以通过 mTLS [RFC8705] 等所有权证明规范进行增强, 以提供所有权证明特征.

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

对持有者令牌的特定结构或格式没有要求, 如第 5 节所述. 如果持有者令牌是对授权信息的引用, 则攻击者必须无法猜测此类引用, 例如使用足够长的加密随机字符串. 如果持有者令牌使用编码机制在令牌本身中包含授权信息, 则访问令牌必须使用足以防止令牌被修改的完整性保护. 你可以在访问令牌的 JSON Web Token 配置文件 [RFC9068] 中找到访问令牌的编码和签名机制的示例.

# 5.2.1. 经过身份验证的请求 Authenticated Requests

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

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

# 5.2.1.1. 授权请求头字段 Authorization Request Header Field

在 HTTP/1.1 [RFC7235] 定义的授权请求标头字段中发送访问令牌时, 客户端使用持有者身份验证方案传输访问令牌.

例如:

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

此方案的授权标头字段的语法遵循 [RFC2617] 第 2 节中定义的基本方案的用法. 请注意, 与 Basic 一样, 它不符合 [RFC2617] 第 1.2 节中定义的通用语法, 但与 HTTP 1.1 身份验证 [RFC7235] 中的常规身份验证框架兼容, 尽管它不遵循其中概述的优先做法以反映现有部署. 持有者凭据的语法如下:

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

客户端应使用具有持有者 HTTP 授权方案的授权请求标头字段, 使用持有者令牌发出经过身份验证的请求. 资源服务器必须支持此方法.

# 5.2.1.2. 表单编码内容参数 Form-Encoded Content Parameter

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

  • Content-Type 设置为 application/x-www-form-urlencoded 的 HTTP 请求.
  • 内容遵循 application/x-www-form-urlencoded 内容类型的编码要求, 如 URL Living Standard [WHATWG.网址].
  • HTTP 请求内容是单部分的.
  • 请求中要编码的内容必须完全由 ASCII [USASCII] 字符组成.
  • HTTP 请求方法是内容已为其定义语义的方法. 需要特别注意的是, 这意味着不得使用 GET 方法.

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

例如, 客户端使用 LTS 发出以下 HTTP 请求:

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

access_token=mF_9.B5f-4.1JqM

不应使用 application/x-www-form-urlencoding 方法, 除非在参与客户端无权访问授权请求标头字段的应用程序上下文中. 资源服务器可能支持此方法.

# 5.2.2. 访问令牌验证 Access Token Validation

收到访问令牌后, 资源服务器必须检查访问令牌是否尚未过期, 是否有权访问所请求的资源, 是否颁发了适当的范围, 以及是否满足资源服务器访问受保护资源的其他策略要求.

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

令牌侦测 ([RFC7662]) 中定义了查询授权服务器以检查访问令牌有效性的标准化方法.

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

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

# 5.2.3. WWW-Authenticate 响应标头字段 The WWW-Authenticate Response Header Field

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

此令牌类型的所有质询都必须使用身份验证方案 Bearer. 此方案后必须跟有一个或多个身份验证参数值. 此规范为此令牌类型使用或定义的身份验证参数属性如下所示. 也可以使用其他身份验证参数属性.

可以包含一个领域属性 realm, 以 HTTP/1.1 [RFC7235] 中所述的方式指示保护范围. 领域属性不得多次出现.

在第 3.2.2.1 节中定义的范围属性 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 属性, 以便向客户端提供访问请求被拒绝的原因. 参数值在第 5.2.4 节中描述. 此外, 资源服务器可能包含 error_description 属性, 以便为开发人员提供人类可读的解释, 该解释不打算向最终用户显示. 它还可能包括带有绝对 URI 的 error_uri 属性, 用于标识解释错误的人类可读网页. error, error_descriptionerror_uri 属性不得多次出现.

scope 属性的值 (在附录 A.4 中指定) 不得包含集合之外的字符 %x21 / %x23-5B / %x5D-7E 用于表示范围值, %x20 用于范围值之间的分隔符. errorerror_description 属性的值 (在附录 A.7 和附录 A.8 中指定) 不得包含集合 %x20-21 / %x23-5B / %x5D-7E 之外的字符. error_uri 属性的值 (在附录 A.9 中指定) 必须符合 URI 引用语法, 因此不得包含集合 %x21 / %x23-5B / %x5D-7E 之外的字符.

例如, 在响应未经身份验证的受保护资源请求时:

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="The access token expired"

# 5.2.4. 错误代码 Error Codes

当请求失败时, 资源服务器将使用相应的 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"

# 5.3. 错误响应 Error Response

如果资源访问请求失败, 资源服务器应将错误通知客户端. 资源服务器执行此操作的方法由特定的令牌类型确定, 例如第 5.2.4 节中对持有者令牌的描述.

# 5.3.1. 扩展令牌类型 Extension Token Types

[RFC6750] 在 [RFC6749] 的第 11.4 节中建立了一个通用注册表, 用于在 OAuth 令牌身份验证方案之间共享错误值.

主要用于 OAuth 令牌身份验证的新身份验证方案应定义一种向客户端提供错误状态代码的机制, 其中允许的错误值在此规范建立的错误注册表中注册.

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

其他能够用于 OAuth 令牌身份验证但主要不是为此目的而设计的方案, 可能会以相同的方式将其错误值绑定到注册表.

新的身份验证方案还可以选择指定使用 error_descriptionerror_uri 参数, 以类似于它们在本规范中的用法的方式返回错误信息.

# 5.4. 发送者限制的访问令牌 Sender-Constrained Access Tokens

受发送方约束的访问令牌将访问令牌的适用范围限定为特定发送方. 此发送方有义务证明知道某个机密 secret, 这是接收方 (例如, 资源服务器) 接受该访问令牌的先决条件.

授权和资源服务器应使用发送方约束访问令牌的机制, 例如 OAuth 2.0 的双向 TLS [RFC8705] 或 OAuth 所有权证明演示 (DPoP) [I-D.ietf-oauth-dpop]. 请参阅 [I-D.ietf-oauth-security-topics] 第 4.10.1 节, 以防止滥用被盗和泄露的访问令牌.

建议在客户端和资源服务器之间使用端到端 TLS. 如果需要在中介处终止 TLS 流量, 请参阅 [I-D.ietf-oauth-security-topics] 的第 4.13 节以获取进一步的安全建议.

# 6, 可扩展性 Extensibility

# 6.1. 定义访问令牌类型 Defining Access Token Types

可以通过以下两种方式之一定义访问令牌类型:

  • 在访问令牌类型注册表中注册 (按照 [RFC6749] 第 11.1 节中的过程)
  • 或使用唯一的绝对 URI 作为其名称.

使用 URI 名称的类型应限制为不常见的特定于供应商的实现, 并且特定于使用它们的资源服务器的实现者的详细信息.

所有其他类型的必须注册. 类型名称必须符合类型名称 ABNF. 如果类型定义包含新的 HTTP 身份验证方案, 则类型名称应与 HTTP 身份验证方案名称 (由 [RFC2617] 定义) 相同. 令牌类型示例保留用于示例.

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

# 6.2. 定义新端点参数 Defining New Endpoint Parameters

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

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

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

未注册的供应商特定参数扩展通常不适用, 并且特定于使用它们的授权服务器的实现者的详细信息, 应使用不太可能与其他注册值冲突的供应商特定前缀 (例如, 以 companyname_ 开头).

# 6.3. 定义新的授权授予类型 Defining New Authorization Grant Types

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

# 6.4. 定义新的授权端点响应类型 Defining New Authorization Endpoint Response Types

按照 [RFC6749] 第 11.3 节中的过程在授权端点响应类型注册表中定义并注册用于授权端点的新响应类型. 响应类型名称必须符合响应类型 ABNF:

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

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

例如, 扩展可以定义和注册代码 other_token 响应类型. 注册后, 同一组合不能注册为 other_token 代码, 但这两个值都可用于表示相同的响应类型.

# 6.5. 定义额外的错误代码 Defining Additional Error Codes

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

如果与扩展错误代码结合使用的扩展是已注册的访问令牌类型, 已注册的端点参数或扩展授权类型, 则必须注册扩展错误代码 ( 按照 [RFC6749] 第 11.4 节中的过程). 与未注册的扩展一起使用的错误代码应当被注册.

错误代码必须符合错误 ABNF, 并且应尽可能以标识名称为前缀. 例如, 标识为扩展参数示例设置的无效值的错误应命名为 example_invalid.

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

# 7. 安全考虑 Security Considerations

作为一个灵活且可扩展的框架, OAuth 的安全考虑取决于许多因素. 以下各节为实施者提供了安全准则, 重点介绍了第 2.1 节中描述的三种客户端类型: Web 应用程序, 基于浏览器的应用程序和原生程序.

全面的 OAuth 安全模型和分析以及协议设计的背景由 [RFC6819] 和 [I-D.ietf-oauth-security-topics] 提供.

# 7.1. 访问令牌安全注意事项 Access Token Security Considerations

# 7.1.1. 安全威胁 Security Threats

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

# 7.1.1.1. 访问令牌制造/修改 Access token manufacture/modification

攻击者可能生成虚假的访问令牌或修改现有令牌的令牌内容 (如身份验证或属性语句), 导致资源服务器向客户端授予不适当的访问权限. 例如, 攻击者可以修改令牌以延长有效期; 恶意客户端可能会修改断言以获取对他们不应查看的信息的访问权限.

# 7.1.1.2. 访问令牌披露 Access token disclosure

访问令牌可能包含包含敏感信息的身份验证和属性语句.

# 7.1.1.3. 访问令牌重定向 Access token redirect

攻击者使用生成的供某一个资源服务器使用的访问令牌来获取对另一个资源服务器的访问权限, 而该服务器错误地认为令牌是对它有效的.

# 7.1.1.4. 访问令牌重放 Access token replay

攻击者尝试使用过去已与该资源服务器一起使用过的访问令牌.

# 7.1.2. 威胁缓解 Threat Mitigation

通过使用数字签名保护访问令牌的内容, 可以缓解各种威胁.

或者, 持有者令牌可以包含对授权信息的引用, 而不是直接对信息进行编码. 使用引用可能需要资源服务器和授权服务器之间的额外交互, 以解析对授权信息的引用. 这种交互的机制不是由这个规范定义的, 但是在令牌内省 [RFC7662] 中定义了这样一个机制.

本文档未指定访问令牌的编码或内容; 因此, 有关保证访问令牌完整性保护的方法的详细建议超出了本规范的范围. 你可以在访问令牌的 JSON Web Token 配置文件 [RFC9068] 中找到访问令牌的编码和签名机制的示例.

若要处理访问令牌重定向, 授权服务器必须在令牌中包含预期收件人 (访问群体 audience ) 的标识, 通常是单个资源服务器 ( 或资源服务器列表). 还建议将令牌的使用限制在特定范围内.

如果在没有 TLS 保护的情况下传输 Cookie, 则其中包含的任何信息都有被披露的风险. 因此, 不记名令牌不得存储在可以明文发送的 cookie 中, 因为其中的任何信息都有被披露的风险. 有关 Cookie 的安全注意事项, 请参阅 “HTTP 状态管理机制” [RFC6265].

在某些部署 (包括使用负载平衡器的部署) 中, 与资源服务器的 TLS 连接在提供资源的实际服务器之前终止 (HTTPS 卸载). 这可能会使 TLS 连接终止的前端服务器与提供资源的后端服务器之间的令牌不受保护. 在此类部署中, 必须采取足够的措施来确保前端和后端服务器之间访问令牌的机密性; 令牌加密就是这样一种可能的措施.

# 7.1.3. 建议摘要 Summary of Recommendations

# 7.1.3.1. 保护不记名令牌 Safeguard bearer tokens

客户端实现必须确保持有者令牌不会泄露给非预期方, 因为它们将能够使用它们来访问受保护的资源. 这是使用持有者令牌时的主要安全注意事项, 也是后续所有更具体建议的基础.

# 7.1.3.2. 验证 TLS 证书链 Validate TLS certificate chains

客户端在向受保护的资源发出请求时必须验证 TLS 证书链. 如果不这样做, 可能会使 DNS 劫持攻击窃取令牌并获得意外访问.

# 7.1.3.3. 始终使用 HTTPS Always use HTTPS

客户端在使用持有者令牌发出请求时必须始终使用 TLS (HTTPS) 或等效的传输安全性. 如果不这样做, 令牌将面临大量攻击, 这些攻击可能会给攻击者带来意外访问权限.

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

# 7.1.3.5. 发行短期不记名令牌 Issue short-lived bearer tokens

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

# 7.1.3.6. 发行有范围限制的不记名令牌 Issue scoped bearer tokens

授权服务器应颁发包含访问群体限制的持有者令牌, 将其使用范围限定为预期的信赖方或一组信赖方.

# 7.1.3.7. 不要在页面 URL 中传递不记名令牌 Don't pass bearer tokens in page URLs

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

# 7.1.4. 访问令牌权限限制 Access Token Privilege Restriction

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

需要特别注意的是, 访问令牌应限制为某些资源服务器 (受众限制 audience restriction), 最好是单个资源服务器. 为了实现这一点, 授权服务器将访问令牌与某些资源服务器相关联, 并且每个资源服务器都有义务验证每个请求发送的访问令牌是否用于该特定资源服务器. 否则, 资源服务器必须拒绝为相应的请求提供服务. 客户端和授权服务器可以分别利用本文和 [RFC8707] 中指定的参数范围或资源来确定它们要访问的资源服务器.

此外, 访问令牌应限制为资源服务器或资源上的某些资源和操作. 为了使其生效, 授权服务器将访问令牌与相应的资源和操作相关联, 并且每个资源服务器都有义务针对每个请求验证随该请求发送的访问令牌是否用于对特定资源的特定操作. 否则, 资源服务器必须拒绝为相应的请求提供服务. 客户端和授权服务器可以利用 [RFC9396] 中指定的参数范围和 authorization_details 来确定这些资源和/或操作.

# 7.2. 客户端认证 Client Authentication

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

例如, 动态注册客户端的身份验证不会证明客户端的身份, 它只能确保从同一客户端实例向授权服务器发出重复请求. 此类客户端在允许请求的范围方面可能受到限制, 或者可能具有其他限制, 例如较短的令牌生存期.

相反, 如果有一个已注册的应用程序, 其开发人员的身份已经过验证, 签署了合同并获得了仅在安全后端服务中使用的客户端机密, 则授权服务器可能允许此客户端请求更敏感的范围或颁发更持久的令牌.

# 7.3. 客户冒充 Client Impersonation

如果机密客户端的凭据被盗, 恶意客户端可以模拟客户端并获取对受保护资源的访问权限.

授权服务器应强制实施显式资源所有者身份验证, 并向资源所有者提供有关客户端以及请求的授权范围和生存期的信息. 由资源所有者在当前客户端的上下文中查看信息, 并授权或拒绝请求.

授权服务器不应在没有对客户端进行身份验证或依赖其他措施来确保重复的请求来自原始客户端而不是模拟者的情况下自动处理重复的授权请求 ( 没有活动资源所有者交互).

# 7.3.1. 模仿原生程序 Impersonation of Native Apps

如上所述, 授权服务器不应在未经用户同意或交互的情况下自动处理授权请求, 除非可以确保客户端的身份. 这包括用户先前已批准给定客户端 ID 的授权请求的情况 - 除非可以证明客户端的身份, 否则应像以前未批准任何请求一样处理请求.

诸如声称的 HTTPS 重定向之类的措施可能会被授权服务器接受为身份证明. 某些操作系统可能会提供替代平台特定的标识功能, 这些功能可能会被接受 (视情况而定).

# 7.3.2. 访问令牌权限限制 Access Token Privilege Restriction

客户端应请求具有所需最小范围的访问令牌. 授权服务器在选择如何遵守请求的范围时应考虑客户端标识, 并且可以颁发范围少于请求范围的访问令牌.

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

需要特别注意的是, 访问令牌应限制为某些资源服务器 (受众限制), 最好是单个资源服务器. 为了实现这一点, 授权服务器将访问令牌与某些资源服务器相关联, 并且每个资源服务器都有义务验证每个请求发送的访问令牌是否用于该特定资源服务器. 否则, 资源服务器必须拒绝为相应的请求提供服务. 客户端和授权服务器可以分别利用 [RFC8707] 中指定的参数范围 scope 或资源 resources 来确定它们要访问的资源服务器.

# 7.4. 客户端冒充资源所有者 Client Impersonating Resource Owner

资源服务器可以根据为其颁发访问令牌的资源所有者的标识或基于客户端凭据授予中的客户端标识做出访问控制决策. 如果这两个选项都可能, 则根据框架实现者的具体情况而定, 此时可能出现客户端的标识被误认为是资源所有者的标识的情况. 例如, 如果客户端能够在向授权服务器注册期间选择自己的 client_id, 则恶意客户端可能会将其设置为标识最终用户的值 (例如, 如果使用 OpenID Connect 中定义的 sub). 如果资源服务器无法正确区分颁发给客户端的访问令牌和颁发给最终用户的访问令牌, 就会导致客户端可能能够访问最终用户的资源.

如果授权服务器具有客户端 ID 和用户标识符的公共命名空间, 导致资源服务器无法区分资源所有者授权的访问令牌和客户端本身授权的访问令牌, 则授权服务器不应允许客户端自由填写其 client_id 或任何其他声明 Claim, 因为这可能导致客户端与真正的资源所有者混淆. 如果无法避免这种情况, 授权服务器必须为资源服务器提供其他方法来区分这两种类型的访问令牌.

# 7.5. 保护授权代码流程 Protecting the Authorization Code Flow

# 7.5.1. 原生程序中的环回重定向注意事项 Loopback Redirect Considerations in Native Apps

环回接口重定向 URI 可以使用 HTTP 协议 (即没有 TLS). 这对于环路接口重定向 URI 来说是可以接受的, 因为 HTTP 请求永远不会离开设备.

客户端应仅在启动授权请求时打开网络端口, 并在返回响应后关闭网络端口.

客户端应仅侦听环回网络接口, 以避免其他网络参与者的干扰.

客户端应使用环回 IP 文本, 而不是第 8.4.2 节中所述的字符串 localhost.

# 7.5.2. HTTP 307 重定向 HTTP 307 Redirect

重定向可能包含用户凭据的请求的授权服务器不得使用 307 状态代码 ([RFC9110] 的第 15.4.8 节) 进行重定向. 如果 HTTP 重定向 (而不是, 例如 JavaScript) 用于此类请求, 则 AS 应使用状态代码 303 (“请参阅其他”).

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

如果状态代码 307 用于重定向, 则用户代理则可能通过 POST 请求将用户凭据发送到客户端.

这会向客户端披露敏感凭据. 如果信赖方是恶意的, 则可以使用该凭据在 AS 上模拟用户.

该行为对于开发人员来说可能是意外的, 但这确实是在 [RFC9110] 的第 15.4.8 节中明确定义的行为. 此状态代码不要求用户代理将 POST 请求重写为 GET 请求, 从而丢弃放在 POST 请求内容中的表单数据.

在 HTTP [RFC9110] 中, 只有状态代码 303 明确地强制将 HTTP POST 请求重写为 HTTP GET 请求. 对于所有其他状态代码, 包括流行的 302 状态代码, 用户代理可以选择不重写 POST 到 GET 请求, 从而向客户端显示用户凭据.
( 但实际上, 大多数用户代理只会在 307 重定向中显示此行为.)

# 7.6. 授权码注入 Authorization Code Injection

授权代码注入是一种中间人攻击方式, 其中客户端在其重定向 URI 中从攻击者那里接收授权代码, 而不是从合法授权服务器接收授权代码. 如果没有适当的保护措施, 客户端就无法知道攻击已经发生. 授权代码注入可能导致攻击者获得对受害者帐户的访问权限, 以及受害者意外获得对攻击者帐户的访问权限.

# 7.6.1. 对策 Countermeasures

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

  • 客户端是机密客户端.
  • 在具体部署和特定请求中, 授权服务器合理地保证客户端正确实现了 OpenID Connect nonce 机制.

即使在这种情况下, 仍然建议使用和强制执行 code_challengecode_verifier.

code_challenge 或 OpenID Connect nonce 值必须是特定于事务的, 并且安全地绑定到启动事务的客户端和用户代理. 如果事务导致错误, 则必须选择 code_challengenonce 的新值.

依靠客户端来验证 OpenID Connect nonce 参数意味着授权服务器无法确认客户端实际上已保护自己免受授权代码注入攻击. 如果攻击者能够将授权代码注入客户端, 客户端仍将交换注入的授权代码并获取令牌, 并且只有在验证随机数 nonce 并看到它不匹配后才会拒绝 ID 令牌. 相比之下, 强制执行 code_challengecode_verifier 参数的授权服务器提供了更高的安全结果, 因为授权服务器能够先发制人地识别授权代码注入攻击, 并避免颁发任何令牌.

历史说明: 尽管 PKCE [RFC7636] (创建 code_challengecode_verifier 参数的位置) 最初设计为保护原生程序免受授权代码泄露攻击的机制, 但所有类型的 OAuth 客户端 (包括 Web 应用程序和其他机密客户端) 都容易受到授权代码注入攻击, 这些攻击都可借助 code_challengecode_verifier 机制解决.

# 7.7. 确保端点真实性 Ensuring Endpoint Authenticity

通过强制使用通道安全机制 (如 [RFC8446]) 与授权和令牌端点通信, 可以降低与中间人攻击相关的风险. 有关更多详细信息, 请参阅第 1.5 节

# 7.8. 凭据猜测攻击 Credentials-Guessing Attacks

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

攻击者猜测生成的令牌 (以及不打算由最终用户处理的其他凭据) 的概率必须小于或等于 2^(-128), 并且应小于或等于 2^(-160).

授权服务器必须利用其他方法来保护供最终用户使用的凭据.

# 7.9. 网络钓鱼攻击 Phishing Attacks

此协议和类似协议的广泛部署可能会导致最终用户习惯于被重定向到要求他们输入密码的网站的做法. 如果最终用户在输入凭据之前无法验证这些网站的真实性, 攻击者就有可能利用这种做法窃取资源所有者的密码.

服务提供商应尝试教育最终用户有关网络钓鱼攻击带来的风险, 并应提供使最终用户易于确认其网站真实性的机制. 客户端开发人员应考虑他们如何与用户代理 (例如, 外部, 嵌入式) 交互的安全影响, 以及最终用户验证授权服务器真实性的能力.

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

# 7.10. 跨站请求伪造 Cross-Site Request Forgery

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

传统的对策是客户端在状态参数中传递一个随机值 (也称为 CSRF 令牌), 如前所述, 该参数将伴随请求链接到重定向 URI 到用户代理会话. [RFC6819] 第 5.3.5 节中详细介绍了此对策. code_verifier 参数或 OpenID Connect nonce 值也可以提供相同的保护能力.

当使用 code_verifier 而不是状态 state 或随机数 nonce 进行 CSRF 保护时, 请务必注意:

  • 客户端必须确保 AS 支持客户端打算使用的 code_challenge_method. 如果授权服务器不支持请求的方法, 则必须改用状态或随机数进行 CSRF 保护.
  • 如果状态 state 用于承载应用程序状态, 并且其内容的完整性是必须的, 则客户端必须保护状态不被篡改和交换. 这可以通过将状态内容绑定到浏览器会话和/或签名/加密的状态值 [I-D.bradley-oauth-jwt-encoded-state] 来实现.

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

# 7.11. 点击劫持 Clickjacking

如 [RFC6819] 的 4.4.1.9 节所述, 授权请求容易受到点击劫持攻击, 也称为用户界面补救 user interface redressing. 在此类攻击中, 攻击者将授权端点用户界面嵌入无害的上下文中, 使用户在与该上下文交互 (例如, 单击按钮) 的过程中产生与授权端点用户界面的交互. 也可以实现相反的结果: 与授权端点交互的用户可能会无意中在覆盖在原始用户界面上的攻击者提供的输入字段中键入密码. 点击劫持攻击可以设计成用户几乎不会注意到的攻击方式, 例如使用几乎不可见的 iframe 覆盖在其他元素之上.

攻击者可以使用此方式获取用户的身份验证凭据, 更改授予客户端的访问范围, 并可能访问用户的资源.

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

为了有效方式此类攻击, 必须在授权端点上启用可用的 CSP 功能, 还必须在用于对用户进行身份验证和授权客户端的其他端点 (例如, 设备授权端点, 登录页面, 错误页面等) 上使用. 这可以防止在支持 CSP 的用户代理中由未经授权的来源 unauthorized origin 进行攻击注入. 客户端可能允许由其重定向端点中使用的源以外的其他源进行界面绘制. 因此, 授权服务器应允许管理员为特定客户端配置允许的源和/或客户端动态注册这些源.

使用 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. 代码注入和输入验证 Code Injection and Input Validation

当未经净化的应用程序使用输入或其他外部变量并导致应用程序逻辑修改时, 就会发生代码注入攻击. 这可能允许攻击者访问应用程序设备或其数据, 造成拒绝服务或引入各种恶意副作用.

授权服务器和客户端必须清理 (并在可能的情况下验证) 收到的任何值 - 需要特别注意的是 stateredirect_uri 参数的值.

# 7.13. 开放式重定向 Open Redirection

开放式重定向器指的是将用户的浏览器转发到从查询参数获取的任意 URI 的端点. 例如, 有时实现此类端点是为了在用户被重定向到外部网站之前显示一条消息, 或者通过登录提示在被打断之前将用户重定向回他们打算访问的 URL.

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

# 7.13.1. 客户端作为开放重定向器 Client as Open Redirector

客户端不得公开开放式重定向器.

攻击者可以使用开放重定向器生成指向客户端的 URL, 并利用它们泄露授权代码, 如 [I-D.ietf-oauth-security-topics] 的第 4.1.1 节所述. 另一种滥用情况是生成似乎指向客户端的 URL. 这可能会诱使用户信任该 URL 并在他们的浏览器中关注它. 这可能会被滥用于网络钓鱼.

为了防止开放式重定向, 客户端应仅在目标 URL 被列入白名单或请求的来源和完整性可以进行身份验证时重定向. OWASP [owasp_redir] 描述了针对开放式重定向的对策.

# 7.13.2. 授权服务器作为开放重定向器 Authorization Server as Open Redirector

与客户端一样, 攻击者可以尝试利用用户对授权服务器 (尤其是其 URL) 的信任来执行网络钓鱼攻击. OAuth 授权服务器会定期将用户重定向到其他网站 (客户端), 但必须以安全的方式执行此操作.

第 4.1.2.1 节已经阻止了开放式重定向, 并指出在 client_idredirect_uri 组合无效的情况下, As 不得自动重定向用户代理.

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

  1. 故意发送错误的授权请求, 例如, 通过使用无效的范围值, 从而指示 AS 将用户代理重定向到其网络钓鱼站点.
  2. 故意发送有效的授权请求, 且 client_idredirect_uri 由攻击者控制. 用户进行身份验证后, AS 会提示用户同意请求. 如果用户注意到请求存在问题并拒绝请求, AS 仍会将用户代理重定向到网络钓鱼站点. 在这种情况下, 无论用户采取何种操作, 用户代理都将被重定向到网络钓鱼站点.
  3. 有意发送有效的静默身份验证请求 (prompt=none), 且 client_idredirect_uri 由攻击者控制. 在这种情况下, AS 会自动将用户代理重定向到网络钓鱼站点. AS 必须采取预防措施来防止这些威胁. AS 必须始终首先对用户进行身份验证, 并且 (静默身份验证用例除外) 在需要时提示用户输入凭据, 然后再重定向用户. 根据其风险评估, AS 需要确定它是否可以信任重定向 URI. 它可以考虑内部或通过某些外部服务完成的 URI 分析, 以评估 URI 背后的可信度和可信度内容, 以及重定向 URI 和其他客户端数据的来源.

仅当 AS 信任重定向 URI 时, AS 才应自动重定向用户代理. 如果 URI 不受信任, AS 可能会通知用户并依赖用户做出正确的决定.

# 7.14. 原生程序中的授权服务器混淆缓解措施 Authorization Server Mix-Up Mitigation in Native Apps

为了防止受损或恶意的授权服务器攻击同一应用使用的另一个授权服务器, 需要为应用使用的每个授权服务器使用唯一的重定向 URI ( 例如, 通过改变路径组件), 并且如果接收授权响应的重定向 URI 与传出授权请求中的重定向 URI 不匹配, 则拒绝授权响应.

原生程序必须将授权请求中使用的重定向 URI 与授权会话数据 (即, 以及状态和其他相关数据) 一起存储, 并且必须验证接收授权响应的 URI 是否与其完全匹配.

第 8.1 节明确要求, 授权服务器拒绝具有与注册内容不匹配的 URI 的请求, 也是防止此类攻击所必需的.

# 8. 原生应用程序 Native Applications

原生应用程序是在资源所有者使用的设备上安装和执行的客户端 (即桌面应用程序, 本机移动应用程序). 原生应用程序需要额外的安全性, 平台功能和整体最终用户体验相关的特殊考虑.

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

原生应用程序可以向操作系统注册的专用协议 schema 来捕获重定向 URI 的响应, 并使用调用客户端作为处理程序, 手动复制和粘贴凭据, 运行本地 Web 服务器, 安装用户代理扩展, 或者通过提供客户端控制下的服务器的重定向 URI 等方式, 使服务端响应可用于原生应用程序.

以前, 原生应用程序通常使用嵌入式用户代理 (通常通过 Web View 实现) 进行 OAuth 授权请求. 这种方法有许多缺点, 包括主机应用能够复制用户凭据和 Cookie, 以及用户需要在每个应用中从头开始进行身份验证. 有关对使用 OAuth 嵌入式用户代理的缺点的深入分析, 请参见第 8.5.1 节.

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

无需更改 OAuth 协议本身即可支持原生应用程序和浏览器之间的授权流程, 因为 OAuth 授权请求和响应是根据 URI 定义. 这也包括可用于应用间通信的 URI. 因此某些假定所有客户端都是机密 Web 客户端的 OAuth 服务器实现则需要额外了解与公共原生应用程序客户端以及它们用于支持此最佳实践的重定向 URI 类型相关的内容.

# 8.1. 本地应用程序客户端的注册 Registration of Native App Clients

除了使用动态客户端注册 [RFC7591] 等机制预配每个实例的密钥外, 原生应用程序应被归类为第 2.1 节中所定义公共客户端, 并必须向授权服务器注册. 授权服务器必须在客户端注册详细信息中记录客户端类型, 以便相应地识别和处理请求.

# 8.1.1. 原生程序的客户端身份验证 Client Authentication of Native Apps

作为嵌入在安装包中以供多个用户使用的密钥不应该被视为可靠的密钥, 因为任意一个用户都可以检查其安装包副本并了解这些被共享的密钥. 因此, 不建议授权服务器要求原生应用程序客户端使用共享密钥对进行客户端身份验证, 因为此时除 client_id 外的其他参数几乎没有价值.

对于仍需要内嵌共享密钥的原生应用程序客户端, 授权服务器必须将其视为第 2.1 节中所定义公共客户端, 并且不接受该密钥作为客户端身份的证明. 如果没有其他措施, 此类客户端可能遭受到客户端模拟攻击 (请参阅第 7.3.1 节).

# 8.2. 在原生程序中使用 OAuth 的应用程序间 URI 通信 Using Inter-App URI Communication for OAuth in Native Apps

正如 URI 用于 Web 上的 OAuth 以启动授权请求并将授权响应返回给请求网站一样, 原生应用可以使用 URI 在设备的浏览器中启动授权请求, 并将响应返回给请求的原生应用.

通过采用 Web 上用于 OAuth 的相同方法, 在 Web 上下文中取得的便利同样可以在原生应用程序上下文中获得, 例如单点登录会话的可用性和单独身份验证上下文的安全性. 重用相同的方法还可以通过依赖不特定于特定平台的基于标准的 Web 流程来降低实现复杂性并提高互操作性.

原生应用程序必须使用外部用户代理来执行 OAuth 授权请求. 这是通过在浏览器中发起授权请求 (详见第 8.3 节) 并使用重定向 URI 来实现的, 该 URI 会将授权响应返回到原生应用程序 (在第 8.4 节中定义).

# 8.3. 从原生程序发起授权请求 Initiating the Authorization Request from a Native App

需要用户授权的原生应用应当根据第 4.1 节创建具有授权代码授予类型的授权请求 URI, 并使用原生应用接收到重定向 URI 的请求.

原生应用授权请求的重定向 URI 的功能类似于基于 Web 的授权请求的功能. 原生应用使用的重定向 URI 不会将授权响应返回到 OAuth 客户端的服务器, 而是将响应返回到应用. 第 8.4 节中记录了重定向 URI 的几种方式, 它们可以实现不同平台中的原生应用程序获取授权响应的功能. 任何允许应用接收并检查其参数的重定向 URI 都是可行的.

构造授权请求 URI 后, 应用使用特定于平台的 API 在外部用户代理中打开 URI. 通常, 使用的外部用户代理是默认浏览器, 即配置为处理系统上的 HTTP 和 HTTPS 协议的 URI 的应用程序; 但是用户也可以选择使用不同的浏览器或其他类别的外部用户代理.

此最佳做法侧重于将浏览器作为原生应用的推荐外部用户代理. 也可以使用专为用户授权设计的外部用户代理, 并且能够像浏览器一样处理授权请求和响应.

其他外部用户代理 (如授权服务器提供的原生应用) 可能满足此最佳做法中规定的条件, 包括使用相同的重定向 URI 属性, 但它们的使用超出了本规范的范围.

某些平台支持称为 “应用内浏览器选项卡” in-app browser tabs 的浏览器功能, 其中应用可以在应用上下文中显示浏览器选项卡, 而无需切换应用, 但仍保留浏览器的主要优势, 例如共享身份验证状态和安全上下文. 在支持它们的平台上, 出于可用性原因, 建议应用使用应用内浏览器选项卡进行授权请求.

译者注: 这项技术在 Android 上被称为 CustomTabs.

# 8.4. 在原生程序中接收授权响应 Receiving the Authorization Response in a Native App

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

# 8.4.1. 声明的 "HTTPS" 协议 URI 重定向 Claimed "HTTPS" Scheme URI Redirection

某些操作系统允许应用在其控制的域中声明 HTTPS URI (请参阅 [RFC9110] 的第 4.2.2 节). 当浏览器遇到已声明的 URI 时, 将使用这个 URI 作为启动参数提供给原生应用, 而不是在浏览器中加载页面.

此类 URI 可由原生应用用作重定向 URI. 授权服务器无法将它们与基于 Web 的常规客户端重定向 URI 区分开来. 例如:

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

由于仅重定向 URI 不足以区分公共原生应用程序客户端和机密 Web 客户端, 因此第 8.1 节要求在客户端注册期间记录客户端类型, 以使服务器能够确定客户端类型并采取相应的措施.

与其他原生应用重定向选项相比, 应用声明的 HTTPS 协议的重定向 URI 具有一些优势, 因为操作系统向授权服务器保证了目标应用的标识. 因此, 原生应用程序应尽可能使用此选项而不是其他选项.

# 8.4.2. 环回接口重定向 Loopback Interface Redirection

无需特殊权限即可在环回网络接口上打开端口的原生应用 (通常是桌面操作系统上的应用) 可以使用环回接口接收 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/oauth2重定向/示例提供程序

虽然使用名称 localhost (即 HTTP://localhost:{port}/{path}) 的重定向 URI 的功能与环回 IP 重定向类似, 但仍不建议使用. 使用环回 IP 文本而不是 localhost 指定重定向 URI 可避免无意中侦听环路接口以外的网络接口. 它也不太容易受到客户端防火墙和用户设备上配置错误的主机名解析的影响.

授权服务器必须允许在请求环回 IP 重定向 URI 时指定任何端口, 以容纳在请求时从操作系统获取可用临时端口的客户端.

客户端不应假定设备支持特定版本的互联网协议. 建议客户端尝试使用任一可用的 IPv4 和 IPv6 环路接口.

# 8.4.3. 私有 URI 协议重定向 Private-Use URI Scheme Redirection

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

许多支持专用 URI 协议的环境不提供声明转移 URI 协议的功能, 也没有阻止其应用使用不属于自己的协议的机制. 因此, 使用专用 URI 协议的客户端容易受到其重定向 URI 的潜在攻击, 因此仅当前面提到的更安全的选项不可用时, 才应使用此选项.

若要使用专用 URI 协议重定向执行授权请求, 原生应用使用标准授权请求启动浏览器, 但重定向 URI 使用它在操作系统中注册的专用 URI 协议.

选择要与应用关联的 URI 协议时, 应用必须使用基于其控制的域名的 URI 协议, 以逆序表示, 如 [RFC7595] 第 3.8 节对专用 URI 协议的建议.

例如, 控制域名 app.example.com 的应用可以使用 com.example.app 作为其协议. 某些授权服务器根据域名 (例如 client1234.usercontent.example.net) 分配客户端标识符, 当以相同的方式逆序时, 这些标识符也可以用作协议的域名. 但是,像 myapp 这样的协议不能满足这一要求, 因为它不是基于域名的.

当同一发布者有多个应用时, 必须注意使每个协议在该组中都是唯一的. 在使用基于逆序域名的应用标识符的平台上, 这些标识符可以重用为 OAuth 重定向的专用 URI 协议, 以帮助避免此问题.

按照 [RFC3986] 第 3.2 节的要求, 由于私有 URI 协议重定向没有命名机构, 因此协议组件后仅显示一个斜杠 (/). 使用专用 URI 协议的重定向 URI 的完整示例如下:

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

当授权服务器完成请求时, 它会像往常一样重定向到客户端的重定向 URI. 由于重定向 URI 使用专用 URI 协议, 因此会导致操作系统启动原生应用, 并将 URI 作为启动参数传入. 然后, 原生应用对授权响应进行正常处理.

# 8.5. 原生程序中的安全注意事项 Security Considerations in Native Apps

# 8.5.1. 原生程序中的嵌入式用户代理 Embedded User Agents in Native Apps

嵌入式用户代理是授权原生应用程序的技术上可行的方法. 根据定义, 这些嵌入式用户代理对于授权服务器的第三方使用是不安全的, 因为托管嵌入式用户代理的应用程序可以访问用户的完整身份验证凭据, 而不仅仅是用于应用程序的 OAuth 授权.

典型的嵌入式用户代理实现方案为嵌入式 Web View, 主机应用程序可以记录在登录表单中输入的每个击键以捕获用户名和密码, 自动提交表单以绕过用户同意, 并复制会话 cookie 并使用它们以用户身份执行经过身份验证的操作.

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

鼓励用户在没有浏览器具有的常用地址栏和可见证书验证功能的情况下在嵌入式用户代理中输入凭据, 使用户无法知道他们是否正在登录合法站点; 即使他们是, 它也会训练他们无需先验证站点即可输入凭据.

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

# 8.5.2. 原生程序中的虚假外部用户代理 Fake External User-Agents in Native Apps

启动授权请求的原生应用程序对用户界面具有很大程度的控制, 并且可能会显示虚假的外部用户代理, 即显示为外部用户代理的嵌入式用户代理.

当所有好人都使用外部用户代理时, 安全专家便可以检测到坏人, 因为任何伪造外部用户代理的人都被证明是坏的. 另一方面, 如果好人和坏人都使用嵌入式用户代理, 那么坏人就不需要伪造任何东西, 这使得他们更难被发现. 一旦检测到恶意应用程序, 就可以使用此知识将应用程序在恶意软件扫描软件中的签名列入黑名单, 采取删除操作 ( 对于应用程序商店分发的应用程序) 和其他步骤来减少恶意应用程序的影响和传播.

授权服务器还可以通过要求身份验证因素仅对真正的外部用户代理可用来直接防范伪造的外部用户代理.

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

# 8.5.3. 原生程序中的恶意外部用户代理 Malicious External User-Agents in Native Apps

如果恶意应用能够将自身配置为操作系统中 HTTPS 协议 URI 的默认处理程序, 那么它将能够拦截使用默认浏览器的授权请求, 并滥用此信任来达到恶意目的, 例如网络钓鱼用户.

这种攻击不仅限于 OAuth; 以这种方式配置的恶意应用将给用户带来超出原生应用使用 OAuth 之外的风险. 许多操作系统通过要求用户显式操作来更改 HTTP 和 HTTPS 协议 URI 的默认处理程序来缓解此问题.

# 9. 基于浏览器的应用程序 Browser-Based Apps

基于浏览器的应用程序是在 Web 浏览器中运行的客户端, 通常用 JavaScript 编写, 也称为 “单页应用程序”. 这些类型的应用具有类似于原生应用的特定安全注意事项.

译者注: 此章节为未完善的章节.

# 10. 与 OAuth 2.0的区别 Differences from OAuth 2.0

本草案整合了 OAuth 2.0 [RFC6749], 用于本机应用程序的 OAuth 2.0 ([RFC8252]), 用于代码交换的证明密钥 ([RFC7636]), 用于基于浏览器的应用程序的 OAuth 2.0 ([I-D.ietf-oauth-browser-based-apps]), OAuth Security Best Current Practice ([I-D.ietf-oauth-security-topics]) 和持有者令牌用法 ([RFC6750]) 中的功能.

如果较晚的草案更新或废弃了原始 [RFC6749] 中的功能, 则此草案中的功能将使用新草案中描述的规范性更改进行更新, 或完全删除.

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

  • 授权代码授予使用 PKCE ([RFC7636]) 的功能进行扩展, 因此根据此规范使用授权代码授予的默认方法需要添加 PKCE 参数
  • 重定向 URI 必须按照 [I-D.ietf-oauth-security-topics] 的第 4.1.3 节使用精确字符串匹配进行比较
  • 根据 [I-D.ietf-oauth-security-topics] 的第 2.1.2 节, 此规范中省略了隐式授权 (response_type=token)
  • 根据 [I-D.ietf-oauth-security-topics] 的第 2.4 节, 此规范中省略了资源所有者密码凭据授予
  • 持有者令牌用法省略了 [I-D.ietf-oauth-security-topics] 第 4.3.2 节中 URI 查询字符串中持有者令牌的使用方式
  • 公共客户端的刷新令牌必须受发件人约束或一次性使用, 如 [I-D.ietf-oauth-security-topics] 的第 4.13.2 节所述
  • 包含授权代码的令牌端点请求不再包含 redirect_uri 参数

# 10.1. 删除 OAuth 2.0 隐式授予 Removal of the OAuth 2.0 Implicit grant

OAuth 2.0 隐式授权在 OAuth 2.1 中被省略, 因为它在 [I-D.ietf-oauth-security-topics] 中被弃用.

删除隐式授权的目的是不再在授权响应中颁发访问令牌, 因为此类令牌容易受到泄漏和注入的影响, 并且无法受客户端的发送方约束. 此行为由使用 response_type=token 参数的客户端指示. OAuth 2.1 中不再定义 response_type 参数的值 token.

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

# 10.2. 令牌请求中的重定向 URI 参数 Redirect URI Parameter in Token Request

在 OAuth 2.0 中, 对授权代码流程中的令牌端点的请求 ([RFC6749] 的第 4.1.3 节) 包含一个可选的 redirect_uri 参数. 该参数旨在防止授权代码注入攻击, 如果在原始授权请求中发送 redirect_uri 参数, 则该参数是必需的. 仅当向特定客户端注册了多个重定向 URI 时, 授权请求才需要 redirect_uri 参数. 但是, 在实践中, 即使客户端只注册了一个 URI, 许多授权服务器实现依然需要授权请求中传递 redirect_uri 参数, 这导致令牌端点也需要传递 redirect_uri 参数.

在 OAuth 2.1 中, code_challengecode_verifier 参数阻止了授权代码注入, 使得包含 redirect_uri 参数在令牌请求中没有任何用处. 因此, 它已被删除.

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

仅遵循 OAuth 2.1 建议的客户端将不会在令牌请求中发送 redirect_uri, 因此与需要令牌请求中的参数的授权服务器不兼容.

# 11. IANA 考虑因素 IANA Considerations

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

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

# 12. 参考文献 References

译者注: 略, 详见 https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-09#name-references .

# 附录 A. 增强巴科斯-诺尔范式 (ABNF) 语法 Appendix A. Augmented Backus-Naur Form (ABNF) Syntax

译者注: 略, 详见 https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-09#name-augmented-backus-naur-form- .

# 附录 B. application/x-www-form-urlencoded 媒体类型的使用 Appendix B. Use of application/x-www-form-urlencoded Media Type

未完待续: 描述 OAuth 对 application/x-www-form-urlencoded 编码的使用, 包括 URL 参数以及 client_idsecret 编码.

GitHub 讨论: https://github.com/oauth-wg/oauth-v2-1/issues/128

# 附录 C. 扩展 Appendix C. Extensions

以下是发布时成熟的扩展列表:

  • [RFC8628]:OAuth 2.0 设备授权授权 OAuth 2.0 Device Authorization Grant 设备授权授予 (以前称为设备流程) 是一种扩展, 使没有浏览器或输入功能受限的设备能够获取访问令牌. 这通常由智能电视应用或硬件视频编码器等设备使用, 这些设备可以将视频流式传输到流视频服务.
  • [RFC8414]:授权服务器元数据 Authorization Server Metadata 授权服务器元数据 (也称为 OAuth 发现) 定义了客户端可用于查找与特定 OAuth 服务器交互所需的信息的端点, 例如授权和令牌端点的位置以及支持的授权类型.
  • [RFC8707]:资源指示器 Resource Indicators 为客户端提供一种向授权服务器显式发出信号的方法, 以使用它所请求的访问令牌.
  • [RFC7591]:动态客户端注册 Dynamic Client Registration 动态客户端注册提供了一种以编程方式向授权服务器注册客户端的机制.
  • [RFC7592]:动态客户端管理 Dynamic Client Management 动态客户端管理提供了一种更新动态注册客户端信息的机制.
  • [RFC9068]:用于 OAuth 2.0 访问令牌的 JWT 配置 JWT Profile for OAuth 2.0 Access Tokens 此规范定义用于以 JSON Web Token (JWT) 格式颁发 OAuth 访问令牌的配置.
  • [RFC8705]:双向 TLS Mutual TLS 双向 TLS 描述了一种机制, 用于将访问令牌和刷新令牌绑定到颁发它们的客户端, 以及通过 TLS 证书身份验证的客户端身份验证机制.
  • [RFC7662]:令牌自检 Token Introspection 令牌自检扩展为资源服务器定义了获取有关访问令牌的信息的机制.
  • [RFC7009]:令牌吊销 Token Revocation 令牌吊销扩展为客户端定义了一种机制, 用于向授权服务器指示不再需要访问令牌.
  • [RFC9126]:推送的授权请求 Pushed Authorization Requests 推送授权请求扩展描述了一种从反向通道启动 OAuth 流程的技术, 为构建复杂的授权请求提供更好的安全性和更强的灵活性.
  • [RFC9207]:授权服务器颁发者标识 Authorization Server Issuer Identification 授权响应中的 iss 参数指示授权服务器的身份, 以防止客户端中的混淆攻击.
  • [RFC9396]:丰富的授权请求 Rich Authorization Requests 丰富授权请求指定一个新参数 authorization_details, 用于在 OAuth 授权请求中携带细粒度授权数据.

# 附录 D. 致谢 Appendix D. Acknowledgements

译者注: 略, 详见 https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-09#name-acknowledgements

# 附录 E. 文档历史记录 Appendix E. Document History

译者注: 略, 详见 https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-09#name-document-history

# 联系方式 Authors' Addresses

Dick Hardt Hellō 电子邮件: dick.hardt@gmail.com

Aaron Parecki Okta 电子邮件: aaron@parecki.com 网址: https://aaronparecki.com

Torsten Lodderstedt yes.com 电子邮件: torsten@lodderstedt.net

# 相关内容

# 推广

欢迎大家尝试使用 Code: Certs | https://code-certs.dengchao.fun (opens new window) 来申请免费的 HTTPS 证书, Code: Certs (opens new window) 还支持自动部署到部分公有云的产品上, 降低 HTTPS 证书运维工作量. 大家遇到什么使用问题或者有任何建议都可以私信我, 或者提交到 https://github.com/code-certs/code-certs/issues (opens new window) 也行.