RFC 9396 OAuth-RAR 2023年5月
Lodderstedt 等 标准轨道 [页]
流:
互联网工程任务组 (IETF)
RFC:
9396
类别:
标准轨道
发布时间:
ISSN:
2070-1721
作者:
T. Lodderstedt
yes.com
J. Richer
Bespoke Engineering
B. Campbell
Ping Identity

RFC 9396

OAuth 2.0 富授权请求

摘要

本文档规定了一个新的参数 authorization_details,该参数 用于在 OAuth 消息中携带细粒度授权数据。

本备忘录的状态

这是一份互联网标准轨道文档。

本文档是互联网工程任务组 (IETF) 的产物。它代表了 IETF 社区的共识。它已经过公开审查,并已由 互联网工程指导组 (IESG) 批准发布。关于互联网标准的 更多信息可在 RFC 7841 第 2 节中获得。

有关本文档当前状态、任何勘误以及如何提供反馈的信息, 可从 https://www.rfc-editor.org/info/rfc9396 获取。

▲

目录

1. 引言

"OAuth 2.0 授权框架" [RFC6749] 定义了 scope 参数,使 OAuth 客户端能够 指定访问令牌所请求的范围,即受限能力。 这种机制足以实现静态场景和 粗粒度授权请求,例如“授予我对 资源所有者资料的读取访问权限”。但是,它不足以指定 细粒度授权要求,例如“请允许我向商户 A 转账 45 欧元” 或“请授予我对目录 A 的读取访问权限以及对文件 X 的写入访问权限”。

本规范引入了一个新的参数 authorization_details, 允许客户端使用 JSON [RFC8259] 数据结构的表达能力来指定其细粒度授权要求。

例如,信用转账的授权请求(在若干开放银行计划中称为“支付 发起”)可以使用如下 JSON 对象来表示:

{
   "type": "payment_initiation",
   "locations": [
      "https://example.com/payments"
   ],
   "instructedAmount": {
      "currency": "EUR",
      "amount": "123.50"
   },
   "creditorName": "Merchant A",
   "creditorAccount": {
      "bic":"ABCIDEFFXXX",
      "iban": "DE02100100109307118603"
   },
   "remittanceInformationUnstructured": "Ref Number Merchant"
}
图 1: 信用转账授权请求示例

该对象包含有关预期支付的详细信息,例如金额、 货币和债权人,这些信息是告知用户并获得其同意所必需的。授权 服务器(AS)和相应的资源服务器(RS)(提供支付发起 API)将共同 执行该同意。

关于开放银行和电子签名领域中新用例所带来挑战的全面 讨论,请参见 [Transaction-Auth]。

除了支持自定义授权请求之外,本规范还 引入了一组可跨不同 API 使用的通用数据类型字段。

1.1. 约定和 术语

本文档中的关键词 "MUST"、"MUST NOT"、"REQUIRED"、"SHALL"、"SHALL NOT"、"SHOULD"、"SHOULD NOT"、"RECOMMENDED"、"NOT RECOMMENDED"、 "MAY" 和 "OPTIONAL" 应按照 BCP 14 [RFC2119] [RFC8174] 中的说明来解释,但前提是它们以全大写形式出现,如此处所示。

本规范使用由 "OAuth 2.0 授权 框架" [RFC6749] 定义的术语:"access token"、"refresh token"、 "authorization server" (AS)、"resource server" (RS)、"authorization endpoint"、 "authorization request"、"authorization response"、"token endpoint"、 "grant type"、"access token request"、"access token response" 和 "client"。

2. 请求参数 "authorization_details"

请求参数 authorization_details 以 JSON 记法包含一个 对象数组。每个 JSON 对象都包含用于指定某种 资源类型的授权要求的数据。资源类型或访问要求由 type 字段决定,其定义如下:

type:
授权详情类型的标识符,表示为 字符串。type 字段的值决定了包含该字段的对象 允许的内容。在 AS 的上下文中,该值对于所描述的 API 是唯一的。此字段为 REQUIRED。

authorization_details 数组 MAY 包含 相同 type 的多个条目。

图 2 展示了一个 使用上面示例数据的 payment_initiation 类型 authorization_details:

[
   {
      "type": "payment_initiation",
      "actions": [
         "initiate",
         "status",
         "cancel"
      ],
      "locations": [
         "https://example.com/payments"
      ],
      "instructedAmount": {
         "currency": "EUR",
         "amount": "123.50"
      },
      "creditorName": "Merchant A",
      "creditorAccount": {
         "iban": "DE02100100109307118603"
      },
      "remittanceInformationUnstructured": "Ref Number Merchant"
   }
]
图 2: 信用转账的 "authorization_details" 示例

图 3 展示了一个组合请求, 请求访问账户信息并请求发起支付的权限:

[
   {
      "type": "account_information",
      "actions": [
         "list_accounts",
         "read_balances",
         "read_transactions"
      ],
      "locations": [
         "https://example.com/accounts"
      ]
   },
   {
      "type": "payment_initiation",
      "actions": [
         "initiate",
         "status",
         "cancel"
      ],
      "locations": [
         "https://example.com/payments"
      ],
      "instructedAmount": {
         "currency": "EUR",
         "amount": "123.50"
      },
      "creditorName": "Merchant A",
      "creditorAccount": {
         "iban": "DE02100100109307118603"
      },
      "remittanceInformationUnstructured": "Ref Number Merchant"
   }
]
图 3: 组合请求的 "authorization_details" 示例

具有 account_information 和 payment_initiation 这两个 type 字段的 JSON 对象表示 AS 用于请求同意的不同 authorization_details。

2.1. 授权详情 类型

AS 控制 type 参数值的解释,以及 type 参数允许的对象字段。但是, type 参数的值通常也会被文档化,并预期供 开发者使用。RECOMMENDED API 设计者选择 易于无歧义复制的 type 值。例如,某些字形对于相同的视觉字符有 多个 Unicode 码位,开发者可能会输入与 AS 所定义字符不同的字符。减少潜在 混淆的可能方法包括将值限制为 ASCII [RFC0020] 字符、提供机器可读的数据 类型值列表,或指示开发者直接从 文档复制并粘贴。

如果某个应用或 API 预期部署在不同服务器之间, 例如开放标准中的情况,则 RECOMMENDED API 设计者 使用其控制下的抗冲突命名空间,例如 API 设计者 控制的 URI。

下面的示例展示了实现如何利用命名空间 https://scheme.example.org/ 来确保类型值抗冲突。

{
   "type": "https://scheme.example.org/files",
   "locations": [
      "https://example.com/files"
   ],
   "permissions": [
      {
         "path": "/myfiles/A",
         "access": [
            "read"
         ]
      },
      {
         "path": "/myfiles/A/X",
         "access": [
            "read",
            "write"
         ]
      }
   ]
}
图 4: 以 URL 作为类型标识符的 "authorization_details" 示例

2.2. 通用数据字段

本规范定义了一组通用数据字段,这些字段设计为可在 不同类型的 API 中使用。本规范不要求 API 定义使用这些 通用字段,而是将其作为可重用的通用组件 提供给 API 设计者使用。所有字段的允许值由 受保护的 API 决定,具体由特定的 "type" 值定义。

locations:
表示资源或 RS 位置的字符串数组。这些字符串通常是标识 RS 位置的 URI。该字段可以允许客户端指定特定 RS,如 第 12 节所述。
actions:
表示要在资源上执行的 动作种类的字符串数组。
datatypes:
表示从资源请求的 数据种类的字符串数组。
identifier:
指示 API 中可用的特定 资源的字符串标识符。
privileges:
表示在资源上请求的权限类型 或权限级别的字符串数组。

当不同通用数据字段组合使用时, 客户端请求的权限是所有值的乘积。 该对象表示请求对象内列出的所有 actions 值 在对象内列出的所有 locations 值处,用于对象内列出的所有 datatypes 值。在下面的示例中,客户端请求对 customer_information API 中属于客户的 contacts 和 photos 同时拥有 read 和 write 访问权限。 如果该请求被授予,客户端 会认为它能够使用 API 所定义的任何权限组合, 例如对照片的读取访问权限以及对 联系人的写入访问权限。

[
   {
      "type": "customer_information",
      "locations": [
         "https://example.com/customers"
      ],
      "actions": [
         "read",
         "write"
      ],
      "datatypes": [
         "contacts",
         "photos"
      ]
   }
]
图 5: 带有通用数据字段的 "authorization_details" 示例

如果客户端希望对其访问有更精细的控制,它可以发送 多个对象。在此示例中, 客户端请求对同一 API 端点中的 contacts 进行 read 访问,并 对 photos 进行 write 访问。 如果该请求被授予,客户端将无法写入联系人。

[
   {
      "type": "customer_information",
      "locations": [
         "https://example.com/customers"
      ],
      "actions": [
         "read"
      ],
      "datatypes": [
         "contacts"
      ]
   },
   {
      "type": "customer_information",
      "locations": [
         "https://example.com/customers"
      ],
      "actions": [
         "write"
      ],
      "datatypes": [
         "photos"
      ]
   }
]
图 6: 多个对象中带有通用数据字段的 "authorization_details" 示例

API MAY 定义其自己的扩展,但受 相应授权对象的 type 约束。 预计 API 设计者将结合使用本规范定义的 通用数据字段以及 API 自身特定的 字段。下面的非规范性 示例展示了作为两个不同虚构 API type 值的一部分, 同时使用通用字段和 API 特定字段。第一个 访问请求包含此处指定的 actions、locations 和 datatypes 字段,以及 API 特定的 geolocation 字段,表示访问在给定坐标拍摄的照片。 第二个访问请求包含此处指定的 actions 和 identifier 字段,以及 API 特定的 currency 字段。

[
   {
      "type":"photo-api",
      "actions":[
         "read",
         "write"
      ],
      "locations":[
         "https://server.example.net/",
         "https://resource.local/other"
      ],
      "datatypes":[
         "metadata",
         "images"
      ],
      "geolocation":[
         {
            "lat":-32.364,
            "lng":153.207
         },
         {
            "lat":-35.364,
            "lng":158.207
         }
      ]
   },
   {
      "type":"financial-transaction",
      "actions":[
         "withdraw"
      ],
      "identifier":"account-14-32-32-3",
      "currency":"USD"
   }
]
图 7: 使用通用和扩展数据字段的 "authorization_details" 示例

如果该请求被批准,生成的访问令牌的访问权限将 是两个 API 各自请求的访问类型的并集,与上文相同。

3. 授权请求

authorization_details 授权请求参数可用于 在所有使用 scope 参数实现相同目的的位置指定授权要求,示例包括:

在 [RFC6749] 定义的授权请求的情况下,实现者 MAY 考虑 使用推送授权请求 [RFC9126] 来 改进流程的安全性、隐私性和可靠性。详见第 12、13 和 11.4 节。

参数编码由相应上下文决定。在根据 [RFC6749] 的 授权请求上下文中,该 参数使用序列化 JSON 的 application/x-www-form-urlencoded 格式进行编码, 如 图 8 所示,使用 第 2 节 中的示例(换行仅用于显示目的):

GET /authorize?response_type=code
   &client_id=s6BhdRkqt3
   &state=af0ifjsldkj
   &redirect_uri=https%3A%2F%2Fclient.example.org%2Fcb
   &code_challenge_method=S256
   &code_challenge=K2-ltc83acc4h0c9w6ESC_rEMTJ3bwc-uCHaoeK1t8U
   &authorization_details=%5B%7B%22type%22%3A%22account%5Finfo
   rmation%22%2C%22actions%22%3A%5B%22list%5Faccounts%22%2C%22
   read%5Fbalances%22%2C%22read%5Ftransactions%22%5D%2C%22loca
   tions%22%3A%5B%22https%3A%2F%2Fexample%2Ecom%2Faccounts%22%
   5D%7D%2C%7B%22type%22%3A%22payment%5Finitiation%22%2C%22act
   ions%22%3A%5B%22initiate%22%2C%22status%22%2C%22cancel%22%5
   D%2C%22locations%22%3A%5B%22https%3A%2F%2Fexample%2Ecom%2Fp
   ayments%22%5D%2C%22instructedAmount%22%3A%7B%22currency%22%
   3A%22EUR%22%2C%22amount%22%3A%22123%2E50%22%7D%2C%22credito
   rName%22%3A%22Merchant%20A%22%2C%22creditorAccount%22%3A%7B
   %22iban%22%3A%22DE02100100109307118603%22%7D%2C%22remittanc
   eInformationUnstructured%22%3A%22Ref%20Number%20Merchant%22
   %7D%5D HTTP/1.1
Host: server.example.com
图 8: 带有 "authorization_details" 的授权请求示例

基于 authorization_details 参数中提供的数据,AS 将请求用户同意所请求的访问权限。

在 图 9 中,客户端希望获得 对账户信息的访问权限并发起支付:

[
   {
      "type": "account_information",
      "actions": [
         "list_accounts",
         "read_balances",
         "read_transactions"
      ],
      "locations": [
         "https://example.com/accounts"
      ]
   },
   {
      "type": "payment_initiation",
      "actions": [
         "initiate",
         "status",
         "cancel"
      ],
      "locations": [
         "https://example.com/payments"
      ],
      "instructedAmount": {
         "currency": "EUR",
         "amount": "123.50"
      },
      "creditorName": "Merchant A",
      "creditorAccount": {
         "iban": "DE02100100109307118603"
      },
      "remittanceInformationUnstructured": "Ref Number Merchant"
   }
]
图 9: URL 解码后的 "authorization_details"

3.1. 与 "scope" 参数的关系

authorization_details 和 scope 可以在 同一个授权请求中用于携带独立的授权要求。

本规范支持 authorization_details 和 scope 的组合使用, 部分原因是允许现有基于 OAuth 的应用逐步迁移到 专门使用 authorization_details。RECOMMENDED 某个给定 API 仅使用一种要求 指定形式。

AS MUST 将这两组要求 彼此结合起来处理,用于给定授权请求。AS 如何 合并这些参数的细节特定于受保护的 API,超出本 规范的范围。

在收集用户同意时,AS MUST 呈现 授权请求所表示的合并后的要求集合。

如果资源所有者授予客户端所请求的访问权限,AS 将 向客户端颁发与相应 authorization_details(以及 scope 值,如适用)关联的令牌。

3.2. 与 "resource" 参数的关系

如 [RFC8707] 中定义的 resource 授权请求参数, 可用于进一步 确定所请求 scope 可应用到哪些资源。resource 参数不会影响 AS 处理 authorization_details 授权请求参数的方式。

4. 授权响应

本规范未定义对授权响应的扩展。

5. 授权错误响应

AS MUST 拒绝处理任何未知授权 详情类型,或不符合相应类型定义的授权详情。若 authorization_details 结构中的对象存在以下任一情况,AS MUST 中止处理并以错误 invalid_authorization_details 响应客户端:

6. 令牌请求

authorization_details 令牌请求参数可用于指定 客户端希望 AS 分配给访问令牌的授权详情。AS 会检查 底层授权(在 authorization_code、 refresh_token 等授权类型的情况下)或客户端策略(在 client_credentials 授权类型的情况下)是否允许颁发具有所请求授权 详情的访问令牌。否则,AS 会以错误码 invalid_authorization_details 拒绝请求(类似于 invalid_scope)。

6.1. 比较 授权详情

OAuth 协议中的许多操作允许 AS 和 RS 基于请求 是否比先前的现有请求要求“更多”或“更少”来做出安全 决策。例如,在刷新令牌时,客户端可以 请求一个权限“少于”资源所有者此前已授权权限的新访问令牌。 所请求的访问令牌将传达减少后的权限,但资源所有者 先前的授权不会因此类请求而改变。 由于 authorization_details 中字段的语义 对给定 API 或 API 集合而言是实现特定的,因此没有 标准化机制可用于比较两个任意授权详情请求。 AS 在大多数情况下不应依赖简单的对象比较,因为请求中某些 字段的交集可能会对授予的访问权限产生副作用, 具体取决于 API 的设计和部署方式。这与某些 API 使用 scope 值时的效果类似。

在将新请求与现有请求比较时,AS 可以使用与 最初授予请求时相同的处理技术,来确定资源 所有者是否需要授权该请求。此比较的细节取决于 授权请求的 type 定义,超出本规范的范围, 但可以应用通用模式。

这将通过贯穿全文的示例来说明。第 3 节 中的示例授权 请求如果由用户批准,则会导致颁发一个与以下权限关联的授权码:

  • 列出账户,
  • 访问一个或多个账户的余额,
  • 访问一个或多个账户的交易,以及
  • 发起、检查状态并取消支付。

客户端现在可以请求 AS 颁发一个仅分配 访问账户列表权限的访问令牌,如下所示:

[
   {
      "type": "account_information",
      "actions": [
         "list_accounts"
      ],
      "locations": [
         "https://example.com/accounts"
      ]
   }
]
图 10: 减少权限的 "authorization_details" 示例

该示例 API 设计为 account_information 类型所使用的每个字段都包含累加权限, actions 和 locations 数组内的每个值 都指定不同的访问元素。为了在此 实例中进行比较,AS 将执行以下步骤:

  • 验证前一步颁发的授权码 包含类型为 account_information 的授权详情对象,
  • 验证已批准的动作列表是否包含 list_accounts,并且
  • 验证 locations 值是否仅包含 先前已批准的位置。

如果所有检查成功,AS 将使用减少后的访问集合 颁发所请求的访问令牌。

请注意,此比较与该特定 API 类型定义相关。 不同的 API 类型定义可能有不同的处理规则。例如,某个 actions 值可能包含与另一个 actions 值关联的权限。例如,如果客户端最初请求具有 write 访问权限的令牌,则这意味着对该 API 同时具有读取和写入访问权限:

[
    {
        "type": "example_api",
        "actions": [
            "write"
        ]
    }
]
图 11: 请求对 API 进行 "write" 访问的 "authorization_details" 示例

之后,同一客户端为 read 访问发起刷新请求:

[
    {
        "type": "example_api",
        "actions": [
            "read"
        ]
    }
]
图 12: 请求对 API 进行 "read" 访问的 "authorization_details" 示例

AS 将比较 type 值和 actions 值,以确定 read 访问已 被此前授予客户端的 write 访问覆盖。

同一个 API 可以设计一个 privileges 的可能值 admin,在此示例中用于 表示生成的令牌被允许对资源执行任何功能。 如果该 客户端随后被授予对此 API 的此类 admin 权限, authorization_details 将如下所示:

[
    {
        "type": "example_api",
        "privileges": [
            "admin"
        ]
    }
]
图 13: 具有对 API 的 "admin" 访问权限的 "authorization_details" 示例

AS 将比较 type 值,并发现 privileges 值涵盖了 此前授予客户端的 read 或 write 访问的任何方面。 请注意,其他 API 定义可以使用 privileges,使得各值并不相互涵盖。

下一个示例展示了客户端如何使用通用数据元素 locations(参见 第 2.2 节)来请求颁发限制到特定 RS 的访问令牌。在我们的 贯穿示例中,客户端可以请求将已批准授权中 payment_initiation 类型的所有权限应用于位于 https://example.com/payments 的 RS,如下所示:

[
   {
      "type": "payment_initiation",
      "locations": [
         "https://example.com/payments"
      ]
   }
]

图 14: 请求受众受限访问令牌的 "authorization_details" 示例

7. 令牌响应

除了 [RFC6749] 中定义的令牌响应参数之外,AS MUST 还返回由资源所有者授予并分配给相应 访问令牌的 authorization_details。

令牌响应中分配给访问令牌的授权详情由 对应令牌请求的 authorization_details 参数决定。如果 客户端未指定 authorization_details 令牌请求参数,AS 可自行决定生成的 authorization_details。

AS MAY 在返回给客户端的 authorization_details 中省略值。

对于我们的贯穿示例,它将如下所示:

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

{
   "access_token": "2YotnFZFEjr1zCsicMWpAA",
   "token_type": "example",
   "expires_in": 3600,
   "refresh_token": "tGzv3JOkF0XG5Qx2TlKWIA",
   "authorization_details": [
      {
         "type": "payment_initiation",
         "actions": [
            "initiate",
            "status",
            "cancel"
         ],
         "locations": [
            "https://example.com/payments"
         ],
         "instructedAmount": {
            "currency": "EUR",
            "amount": "123.50"
         },
         "creditorName": "Merchant A",
         "creditorAccount": {
            "iban": "DE02100100109307118603"
         },
         "remittanceInformationUnstructured": "Ref Number Merchant"
      }
   ]
}
图 15: 令牌响应示例

7.1. 令牌响应中的增强授权 详情

附加到访问令牌的授权详情 MAY 与客户端请求的内容不同。除了用户 授权少于客户端请求的内容之外,在某些用例中,AS 会增强 授权详情对象中的数据。是否允许增强以及 其工作方式的具体细节必然属于相应授权详情类型定义的一部分。

举一个例子,客户端可能请求访问账户信息,但将 其能够访问哪些具体账户的决定留给用户。在 授权过程期间,用户会选择他们 希望允许客户端访问的账户子集。作为传达所选账户的一种设计选项, AS 可以将此信息添加到相应的授权详情对象中。

在该示例中,请求的 authorization_details 参数 可能如下所示。在此示例中,空数组充当占位符,表示 AS 进行增强时将添加数据的位置。此示例仅用于说明,并不 旨在建议以这种方式设计任何授权详情类型的具体细节。

"authorization_details": [
   {
      "type": "account_information",
      "access": {
         "accounts": [],
         "balances": [],
         "transactions": []
      },
      "recurringIndicator":true
   }
]
图 16: 所请求 "authorization_details" 的示例

随后,AS 将扩展授权详情对象并添加 相应的账户标识符。

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

{
   "access_token":"2YotnFZFEjr1zCsicMWpAA",
   "token_type":"example",
   "expires_in":3600,
   "refresh_token":"tGzv3JokF0XG5Qx2TlKWIA",
   "authorization_details":[
      {
         "type":"account_information",
         "access":{
            "accounts":[
               {
                  "iban":"DE2310010010123456789"
               },
               {
                  "maskedPan":"123456xxxxxx1234"
               }
            ],
            "balances":[
               {
                  "iban":"DE2310010010123456789"
               }
            ],
            "transactions":[
               {
                  "iban":"DE2310010010123456789"
               },
               {
                  "maskedPan":"123456xxxxxx1234"
               }
            ]
         },
         "recurringIndicator":true
      }
   ]
}
图 17: 增强后 "authorization_details" 的示例

再举一个例子,客户端请求访问一份医疗记录,但 在请求时不知道记录编号。在此示例中,客户端指定它 想要的访问类型,但未指定该访问的位置或标识符。

{
"authorization_details": [
   {
      "type": "medical_record",
      "sens": [ "HIV", "ETH", "MART" ],
      "actions": [ "read" ],
      "datatypes": [ "Patient", "Observation", "Appointment" ]
   }
]}
图 18: 所请求 "authorization_details" 的示例

当用户与 AS 交互时,他们选择哪些医疗记录 由其负责提供给客户端。此信息会随访问 令牌一起返回。

{
   "access_token":"2YotnFZFEjr1zCsicMWpAA",
   "token_type":"example",
   "expires_in":3600,
   "refresh_token":"tGzv3JokF0XG5Qx2TlKWIA",
   "authorization_details":[
    {
      "type": "medical_record",
      "sens": [ "HIV", "ETH", "MART" ],
      "actions": [ "read" ],
      "datatypes": [ "Patient", "Observation", "Appointment" ],
      "identifier": "patient-541235",
      "locations": [ "https://records.example.com/" ]
     }
  ]
}
图 19: 增强后 "authorization_details" 的示例

8. 令牌错误响应

令牌错误响应 MUST 符合 第 5 节 中给出的规则。

9. 资源服务器

为了使 RS 能够执行授权过程中批准的授权详情, AS MUST 将这些数据提供给 RS。AS MAY 将 authorization_details 字段添加到 JSON Web Token (JWT) 格式的访问令牌中,或添加到令牌自省响应中。

9.1. 基于 JWT 的访问 令牌

如果访问令牌是 JWT [RFC7519],则 RECOMMENDED AS 将针对特定受众过滤后的授权详情对象添加为顶层 声明。

AS 通常还会向 JWT 添加 RS 处理请求所需的其他 声明,例如用户 ID、角色和交易特定数据。特定 RS 需要哪些声明由该 RS 与 AS 之间的特定策略定义。

下面展示了上述支付发起 示例的一个示例 JWT 内容:

{
   "iss": "https://as.example.com",
   "sub": "24400320",
   "aud": "a7AfcPcsl2",
   "exp": 1311281970,
   "acr": "psd2_sca",
   "txn": "8b4729cc-32e4-4370-8cf0-5796154d1296",
   "authorization_details": [
      {
         "type": "https://scheme.example.com/payment_initiation",
         "actions": [
            "initiate",
            "status",
            "cancel"
         ],
         "locations": [
            "https://example.com/payments"
         ],
         "instructedAmount": {
            "currency": "EUR",
            "amount": "123.50"
         },
         "creditorName": "Merchant A",
         "creditorAccount": {
            "iban": "DE02100100109307118603"
         },
         "remittanceInformationUnstructured": "Ref Number Merchant"
      }
   ],
   "debtorAccount": {
      "iban": "DE40100100103307118608",
      "user_role": "owner"
   }
}
图 20: 基于 JWT 的访问令牌中的 "authorization_details" 示例

在这种情况下,AS 向基于 JWT 的 访问令牌添加了以下示例声明:

sub:
指示客户端正在为其 请求支付发起的用户。
txn:
用于在提供者 example.com 的各服务之间跟踪交易的交易 ID
debtorAccount:
包含债务人账户的 API 特定字段。 在该示例中,此账户并未在 authorization_details 中传递,而是由用户在授权 过程中选择的。user_role 字段传达用户相对于该 特定账户所具有的角色。在这种情况下,他们是所有者。此数据用于 支付 API(RS)处的访问控制。

9.2. 令牌自省

令牌自省 [RFC7662] 提供了一种手段,使 RS 能够查询 AS 以 确定有关访问令牌的信息。如果 AS 在其响应中包含该令牌的授权详情信息, 则该信息 MUST 以 authorization_details 作为自省响应 JSON 对象的顶层成员来传达。authorization_details 成员 MUST 包含 第 2 节 中定义的相同结构, 可能会针对发起自省请求的 RS 进行过滤和扩展。

下面是支付发起 示例的一个自省响应示例:

{
   "active": true,
   "sub": "24400320",
   "aud": "s6BhdRkqt3",
   "exp": 1311281970,
   "acr": "psd2_sca",
   "txn": "8b4729cc-32e4-4370-8cf0-5796154d1296",
   "authorization_details": [
      {
         "type": "https://scheme.example.com/payment_initiation",
         "actions": [
            "initiate",
            "status",
            "cancel"
         ],
         "locations": [
            "https://example.com/payments"
         ],
         "instructedAmount": {
            "currency": "EUR",
            "amount": "123.50"
         },
         "creditorName": "Merchant123",
         "creditorAccount": {
            "iban": "DE02100100109307118603"
         },
         "remittanceInformationUnstructured": "Ref Number Merchant"
      }
   ],
   "debtorAccount": {
      "iban": "DE40100100103307118608",
      "user_role": "owner"
   }
}
图 21: 自省响应中的 "authorization_details" 示例

10. 元数据

为了通告其对此特性的支持,授权详情 类型的受支持列表通过元数据参数 authorization_details_types_supported 包含在 AS 元数据响应 [RFC8414] 中,该参数是一个 JSON 数组。

下面的示例对此进行了说明:

{
   ...
   "authorization_details_types_supported":[
      "payment_initiation",
      "account_information"
   ]
}
图 22: 关于受支持授权详情的服务器元数据示例

客户端 MAY 使用客户端注册元数据参数 authorization_details_types 指示它们在请求授权时 将使用的授权详情类型,该参数是一个 JSON 数组。

下面的示例对此进行了说明:

{
   ...
   "authorization_details_types":[
      "payment_initiation"
   ]
}
图 23: 关于 授权详情的服务器元数据示例

向 AS 注册授权详情类型超出 本规范的范围。

11. 实现考虑事项

11.1. 在特定部署中使用授权 详情

在特定部署中使用授权详情将需要 以下步骤:

  • 定义授权详情类型。
  • 在 OAuth 服务器 元数据中发布授权详情类型。
  • 确定授权详情如何在 用户同意提示中显示给用户。
  • 如有需要,在用户 同意过程中增强授权详情(例如添加选定账户或设置过期时间)。
  • 如有需要,确定授权详情如何 反映在访问令牌内容或自省响应中。
  • 确定 RS 如何处理授权详情 或从授权详情派生的令牌数据。
  • 如有需要,授权客户端使用某些授权 详情类型。

11.2. 最小实现 支持

支持本规范的通用 AS 实现应提供 以下基本功能:

  • 支持在 OAuth 服务器元数据中公告受支持的授权 详情类型
  • 根据本规范接受授权请求中的 authorization_details 参数
  • 支持将已同意的授权详情作为 授权的一部分进行存储
  • 实现用于将授权 详情添加到访问令牌和令牌自省响应的默认行为,以便使其可供 RS 使用(类似于 scope 值)。这应适用于任何授权类型,尤其是 authorization_code 和 refresh_token。

不同授权详情类型之间,授权详情的处理和呈现将有显著差异。 因此,实现应支持对相应行为进行 自定义。特别是,实现应允许 部署:

  • 确定授权详情的呈现;
  • 在用户 同意过程中修改请求的授权详情,例如添加字段;以及
  • 合并请求的和预先存在的授权 详情。

支持此类自定义的一种方法是提供一种机制, 允许注册扩展模块,每个模块负责呈现 相应的用户同意,并负责为通过 结构化访问令牌或令牌自省响应向 RS 提供所需数据而进行的任何转换。

11.3. 机器可读类型模式的使用

实现可以允许部署使用机器可读模式 语言来定义授权详情类型,以便根据此类模式创建和验证 授权详情对象。例如,如果某个授权详情 type 使用 JSON Schema [JSON.Schema] 来定义,则该 JSON Schema 标识符可用作 相应授权详情对象中的 type 值。

不过请注意,type 值是 AS 以及必要时客户端和 RS 所理解的标识符。 本规范不假设 type 值会指向 机器可读模式格式,也不假设系统中的任何一方(例如客户端、AS 或 RS) 会以任何特定方式解引用或处理 type 字段的内容。

11.4. 大型请求

包含作为请求参数或请求对象中的 authorization_details 的授权请求 URI 可能会变得很长。因此,实现者应 考虑使用 [RFC9101] 中定义的 request_uri 参数,并结合 [RFC9126] 中定义的推送请求对象 机制,以可靠且安全的方式传递 authorization_details。下面是此类 推送授权请求的示例,它通过受 HTTPS 保护的连接将授权请求数据直接发送给 AS:

  POST /as/par HTTP/1.1
  Host: as.example.com
  Content-Type: application/x-www-form-urlencoded
  Authorization: Basic czZCaGRSa3F0Mzo3RmpmcDBaQnIxS3REUmJuZlZkbUl3

  response_type=code&
  client_id=s6BhdRkqt3
  &state=af0ifjsldkj
  &redirect_uri=https%3A%2F%2Fclient.example.org%2Fcb
  &code_challenge_method=S256
  &code_challenge=K2-ltc83acc4h0c9w6ESC_rEMTJ3bwc-uCHaoeK1t8U
  &authorization_details=%5B%7B%22type%22%3A%22account_information%22
  %2C%22actions%22%3A%5B%22list_accounts%22%2C%22read_balances%22%2C%
  22read_transactions%22%5D%2C%22locations%22%3A%5B%22https%3A%2F%2Fe
  xample.com%2Faccounts%22%5D%7D%2C%7B%22type%22%3A%22payment_initiat
  ion%22%2C%22actions%22%3A%5B%22initiate%22%2C%22status%22%2C%22canc
  el%22%5D%2C%22locations%22%3A%5B%22https%3A%2F%2Fexample.com%2Fpaym
  ents%22%5D%2C%22instructedAmount%22%3A%7B%22currency%22%3A%22EUR%22
  %2C%22amount%22%3A%22123.50%22%7D%2C%22creditorName%22%3A%22Merchan
  t123%22%2C%22creditorAccount%22%3A%7B%22iban%22%3A%22DE021001001093
  07118603%22%7D%2C%22remittanceInformationUnstructured%22%3A%22Ref%2
  0Number%20Merchant%22%7D%5D
图 24: 包含 "authorization_details" 的大型请求示例

12. 安全考虑事项

在 OAuth 授权请求的情况下, authorization_details 参数会通过用户代理发送,这使其容易受到用户修改的影响。如果 authorization_details 的完整性是一个关注点,则客户端 MUST 保护 authorization_details 免受篡改和替换。这可以通过使用 [RFC9101] 中定义的签名请求对象对请求进行签名来实现,或结合 [RFC9126] 使用 [RFC9101] 中定义的 request_uri 授权 请求参数,将请求对象的 URI 传递给 AS。

authorization_details 参数中的所有字符串比较都要 按照 [RFC8259] 的定义执行。在评估字符串值等价性时,不得执行额外的 转换或规范化。

通用数据字段 locations 允许客户端指定其 打算在何处使用某项授权,即可以将权限明确分配给 RS。 在有多个 RS 的情况下,这通过 受众限制防止了无意的客户端授权(例如,某个 read scope 值可能同时适用于电子邮件以及云服务)。

AS MUST 正确清理和处理 authorization_details 中传递的数据,以防止注入攻击。

[RFC6749]、[RFC7662] 和 [RFC8414] 的安全考虑事项同样适用。

13. 隐私考虑事项

实现者以保护隐私的方式设计和使用授权详情 尤其重要。

必须防止 authorization_details 中包含的任何敏感个人数据 泄漏,例如通过 referrer 头泄漏。实现选项包括使用 [RFC9101] 中定义的加密请求对象,或通过利用 [RFC9126] 以及 [RFC9101] 中定义的 request_uri 授权请求参数, 在客户端和 AS 之间通过端到端加密连接传输 authorization_details。后一种方式不需要应用级加密, 但它需要客户端和 AS 之间进行另一次消息交换。

即使请求数据已加密,攻击者仍可能通过 AS 来获知用户 数据:将加密请求数据注入到其控制的设备上的授权请求中, 并使用 AS 的用户同意屏幕以明文显示(解密后的)用户数据。 实现需要考虑此攻击向量并实施适当的对策,例如 只显示部分数据,或在可能的情况下确定假定的用户上下文是否仍然 相同(在用户认证之后)。

AS 在与客户端或 RS 共享 authorization_details 时,需要考虑隐私影响。AS 应按照本地策略确定的 “需要知道”原则与这些方共享此数据。

14. IANA 考虑事项

14.1. OAuth 参数 注册

以下参数已注册到 由 [RFC6749] 建立的 "OAuth Parameters" 注册表 [IANA.OAuth.Parameters] 中。

名称:
authorization_details
参数使用位置:
授权请求、令牌请求、令牌 响应
变更控制方:
IETF
参考:
RFC 9396

14.2. JSON Web Token 声明 注册

以下值已注册到 由 [RFC7519] 建立的 IANA "JSON Web Token Claims" 注册表中。

声明名称:
authorization_details
声明描述:
声明 authorization_details 包含一个 JSON 对象数组,表示访问令牌的 权限。每个 JSON 对象包含用于指定 某种资源类型的授权要求的数据。
变更控制方:
IETF
参考:
RFC 9396 的 第 9.1 节

14.3. OAuth 令牌 自省响应注册

以下值已注册到由 [RFC7662] 建立的 IANA "OAuth Token Introspection Response" 注册表中。

名称:
authorization_details
描述:
成员 authorization_details 包含一个 JSON 对象数组,表示访问令牌的 权限。每个 JSON 对象包含用于指定 某种资源类型的授权要求的数据。
变更控制方:
IETF
参考:
RFC 9396 的 第 9.2 节

14.4. OAuth 授权 服务器元数据注册

以下值已注册到由 [RFC8414] 建立的 [IANA.OAuth.Parameters] 的 IANA "OAuth Authorization Server Metadata" 注册表中。

元数据名称:
authorization_details_types_supported
元数据描述:
包含 AS 支持的授权 详情类型的 JSON 数组
变更控制方:
IETF
参考:
RFC 9396 的 第 10 节

14.5. OAuth 动态客户端 注册元数据注册

以下值已注册到由 [RFC7591] 建立的 [IANA.OAuth.Parameters] 的 IANA "OAuth Dynamic Client Registration Metadata" 注册表中。

客户端元数据名称:
authorization_details_types
客户端元数据描述:
指示客户端使用哪些授权详情类型。
变更控制方:
IETF
参考:
RFC 9396 的 第 10 节

14.6. OAuth 扩展错误 注册

以下值已注册到由 [RFC6749] 建立的 [IANA.OAuth.Parameters] 的 IANA "OAuth Extensions Error Registry" 中。

名称:
invalid_authorization_details
使用位置:
令牌端点、授权端点
协议扩展:
OAuth 2.0 富授权请求
变更控制方:
IETF
参考:
RFC 9396 的 第 5 节

15. 参考文献

15.1. 规范性参考文献

[RFC2119]
Bradner, S., "RFC 中用于表示要求级别的 关键词", BCP 14, RFC 2119, DOI 10.17487/RFC2119, , <https://www.rfc-editor.org/info/rfc2119>.
[RFC7519]
Jones, M., Bradley, J., and N. Sakimura, "JSON Web Token (JWT)", RFC 7519, DOI 10.17487/RFC7519, , <https://www.rfc-editor.org/info/rfc7519>.
[RFC7662]
Richer, J., Ed., "OAuth 2.0 令牌 自省", RFC 7662, DOI 10.17487/RFC7662, , <https://www.rfc-editor.org/info/rfc7662>.
[RFC8174]
Leiba, B., "RFC 2119 关键词中 大写与小写的歧义", BCP 14, RFC 8174, DOI 10.17487/RFC8174, , <https://www.rfc-editor.org/info/rfc8174>.
[RFC8414]
Jones, M., Sakimura, N., and 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., and H. Tschofenig, "OAuth 2.0 设备授权许可", RFC 8628, DOI 10.17487/RFC8628, , <https://www.rfc-editor.org/info/rfc8628>.
[RFC8707]
Campbell, B., Bradley, J., and H. Tschofenig, "OAuth 2.0 的资源指示符", RFC 8707, DOI 10.17487/RFC8707, , <https://www.rfc-editor.org/info/rfc8707>.

15.2. 资料性参考文献

[CSC]
Cloud Signature Consortium, "远程签名应用的架构和 协议", 版本 1.0.4.0, , <https://cloudsignatureconsortium.org/wp-content/uploads/2020/01/CSC_API_V1_1.0.4.0.pdf>.
[ETSI]
ETSI, "电子签名和 基础设施 (ESI);远程数字签名创建协议", V1.1.1, ETSI TS 119 432, , <https://www.etsi.org/deliver/etsi_ts/119400_119499/119432/01.01.01_60/ts_119432v010101p.pdf>.
[IANA.OAuth.Parameters]
IANA, "OAuth 参数", <https://www.iana.org/assignments/oauth-parameters>.
[JSON.Schema]
OpenJS Foundation, "JSON Schema", <https://json-schema.org/>.
[OID-CIBA]
Fernandez, G., Walter, F., Nennker, A., Tonge, D., and B. Campbell, "OpenID Connect 客户端发起的 后通道身份验证流程 - Core 1.0", , <https://openid.net/specs/openid-client-initiated-backchannel-authentication-core-1_0.html>.
[OIDC]
Sakimura, N., Bradley, J., Jones, M., de Medeiros, B., and C. Mortimore, "OpenID Connect Core 1.0 合并勘误集 1", , <https://openid.net/specs/openid-connect-core-1_0.html>.
[RFC0020]
Cerf, V., "网络 交换的 ASCII 格式", STD 80, RFC 20, DOI 10.17487/RFC0020, , <https://www.rfc-editor.org/info/rfc20>.
[RFC6749]
Hardt, D., Ed., "OAuth 2.0 授权 框架", RFC 6749, DOI 10.17487/RFC6749, , <https://www.rfc-editor.org/info/rfc6749>.
[RFC7591]
Richer, J., Ed., Jones, M., Bradley, J., Machulak, M., and P. Hunt, "OAuth 2.0 动态客户端注册 协议", RFC 7591, DOI 10.17487/RFC7591, , <https://www.rfc-editor.org/info/rfc7591>.
[RFC8259]
Bray, T., Ed., "JavaScript Object Notation (JSON) 数据交换格式", STD 90, RFC 8259, DOI 10.17487/RFC8259, , <https://www.rfc-editor.org/info/rfc8259>.
[RFC9101]
Sakimura, N., Bradley, J., and M. Jones, "OAuth 2.0 授权 框架:JWT 保护的授权请求 (JAR)", RFC 9101, DOI 10.17487/RFC9101, , <https://www.rfc-editor.org/info/rfc9101>.
[RFC9126]
Lodderstedt, T., Campbell, B., Sakimura, N., Tonge, D., and F. Skokan, "OAuth 2.0 推送授权 请求", RFC 9126, DOI 10.17487/RFC9126, , <https://www.rfc-editor.org/info/rfc9126>.
[Transaction-Auth]
Lodderstedt, T., "交易授权,或为什么我们需要重新思考 OAuth scopes", , <https://medium.com/oauth-2/transaction-authorization-or-why-we-need-to-re-think-oauth-scopes-2326e2038948>.

附录 A. 其他示例

A.1. OpenID Connect

OpenID Connect [OIDC] 指定了基于 JSON 的 claims 请求参数,可用于以细粒度 且保护隐私的方式指定客户端(作为 OpenID Connect Relying Party)希望接收的 声明,并将这些声明分配给某些传递机制,即 ID Token 或 userinfo 响应。

scope 值 openid 与附加 参数 claims 的组合,可以像任何非 OIDC scope 值一样,与 authorization_details 一起使用。

或者,也可以为 OpenID Connect 设置一种授权详情类型。本节给出了这种授权详情类型可能 是什么样子的示例,但定义此授权详情类型超出本规范的范围。

这些假设示例试图将授权过程中 OpenID Connect 部分特有的所有细节封装到授权 JSON 对象中。

顶层字段基于 [OIDC] 中给出的定义:

claim_sets:
预定义声明集的名称, 替代相应的 scope 值,例如 profile
max_age:
最大认证年龄
acr_values:
请求的认证上下文类 引用(ACR)值
claims:
如 [OIDC] 中定义的 claims JSON 结构

这是对若干声明集的简单请求。

[
   {
      "type": "openid",
      "locations": [
         "https://op.example.com/userinfo"
      ],
      "claim_sets": [
         "email",
         "profile"
      ]
   }
]
图 25: 利用 "authorization_details" 的 OpenID Connect 请求示例

图 26 展示了一个更复杂的示例。

[
   {
      "type": "openid",
      "locations": [
         "https://op.example.com/userinfo"
      ],
      "max_age": 86400,
      "acr_values": "urn:mace:incommon:iap:silver",
      "claims": {
         "userinfo": {
            "given_name": {
               "essential": true
            },
            "nickname": null,
            "email": {
               "essential": true
            },
            "email_verified": {
               "essential": true
            },
            "picture": null,
            "http://example.com/claims/groups": null
         },
         "id_token": {
            "auth_time": {
               "essential": true
            }
         }
      }
   }
]
图 26: 利用 "authorization_details" 的 OpenID Connect 请求高级示例

A.2. 远程电子 签名

以下示例基于 ETSI TS 119 432 [ETSI] 中提出的远程电子 签名概念,以及用于远程签名创建的 Cloud Signature Consortium (CSC) API [CSC]。

[
   {
      "type": "sign",
      "locations": [
         "https://signing.example.com/signdoc"
      ],
      "credentialID": "60916d31-932e-4820-ba82-1fcead1c9ea3",
      "documentDigests": [
         {
            "hash": "sTOgwOm+474gFj0q0x1iSNspKqbcse4IeiqlDg/HWuI=",
            "label": "Credit Contract"
         },
         {
            "hash": "HZQzZmMAIWekfGH0/ZKW1nsdt0xg3H6bZYztgsMTLw0=",
            "label": "Contract Payment Protection Insurance"
         }
      ],
      "hashAlgorithmOID": "2.16.840.1.101.3.4.2.1"
   }
]
图 27: 电子 签名示例

顶层字段具有以下含义:

credentialID:
要用于 签名的证书标识符
documentDigests:
包含每个待签名文档 哈希(hash 字段)的数组。此外,对应的 label 字段向用户标识相应文档,例如用于用户同意。
hashAlgorithm:
用于计算 哈希值的算法

AS 应请求用户同意为该结构中列出的 文档创建签名。客户端使用作为该过程结果颁发的访问令牌 调用相应签名服务处的文档签名 API,以实际 创建签名。该访问令牌绑定到客户端、用户 ID 以及用户 已同意的哈希(和签名算法)。

A.3. 访问税务数据

此示例受到允许第三方访问公民 税务申报和收入报表的 API 启发,例如用于确定其信用状况。

[
    {
        "type": "tax_data",
        "locations": [
            "https://taxservice.govehub.no.example.com"
        ],
        "actions":"read_tax_declaration",
        "periods": ["2018"],
        "duration_of_access": 30,
        "tax_payer_id": "23674185438934"
    }
]
图 28: 税务数据访问示例

顶层字段具有以下含义:

periods:
客户端希望访问的期间
duration_of_access:
客户端打算访问数据的时长, 以天为单位
tax_payer_id:
纳税人的标识符(如果客户端知道)

A.4. 电子健康

这两个示例受到挪威电子健康系统中使用的 API 要求启发。

在此用例中,物理治疗师坐在自己的计算机前, 使用本地电子健康记录(EHR)系统。他们希望查看某个患者的电子 患者记录,并且还希望从另一个系统(可能在另一个机构或国家服务中) 获取患者的病历条目。对此类数据的访问由 API 提供。

在 API 处授权该请求所需的信息仅由 EHR 系统知道,并且必须提交给 API。

在第一个示例中,授权详情对象包含一个 组织的标识符。在这种情况下,API 需要知道给定组织是否具有 处理个人健康信息以访问敏感数据的合法依据。

"authorization_details": {
    "type": "patient_record",
    "requesting_entity": {
        "type": "Practitioner",
        "identifier": [
        {
            "system": "urn:oid:2.16.578.1.12.4.1.4.4",
            "value": "1234567"
        }],
        "practitioner_role": {
            "organization": {
                "identifier": {
                    "system": "urn:oid:2.16.578.1.12.4.1.2.101",
                    "type": "ENH",
                    "value": "[organizational number]"
                }
            }
        }
    }
}
图 29: 电子健康示例

在第二个示例中,API 需要更多信息来授权 请求。在这种情况下,授权详情对象包含有关 健康机构以及用户在请求时当前职业的附加信息。 这一额外详细级别可同时用于授权和数据最小化。

[
   {
      "type": "patient_record",
      "location": "https://fhir.example.com/patient",
      "actions": [
         "read"
      ],
      "patient_identifier": [
         {
            "system": "urn:oid:2.16.578.1.12.4.1.4.1",
            "value": "12345678901"
         }
      ],
      "reason_for_request": "Clinical treatment",
      "requesting_entity": {
         "type": "Practitioner",
         "identifier": [
            {
               "system": "urn:oid:2.16.578.1.12.4.1.4.4",
               "value": "1234567"
            }
         ],
         "practitioner_role": {
            "organization": {
               "identifier": [
                  {
                     "system": "urn:oid:2.16.578.1.12.4.1.2.101",
                     "type": "ENH",
                     "value": "<organizational number>"
                  }
               ],
               "type": {
                  "coding": [
                     {
                        "system":
                           "http://hl7.example.org/fhir/org-type",
                        "code": "dept",
                        "display": "Hospital Department"
                     }
                  ]
               },
               "name": "Akuttmottak"
            },
            "profession": {
               "coding": [
                  {
                     "system": "http://snomed.example.org/sct",
                     "code": "36682004",
                     "display": "Physical therapist"
                  }
               ]
            }
         }
      }
   }
]
图 30: 高级电子健康示例

字段描述:

patient_identifier:
由 OID 格式的系统标识符(命名空间)和 该命名空间内实际值组成的患者标识符。
reason_for_request:
用户希望访问某个 API 的原因。
requesting_entity:
通过 身份、角色和组织上下文来说明请求者。提供此数据是为了便利授权 以及用于审计目的。

在此用例中,AS 对请求者进行身份验证,该请求者不是 患者,并基于策略批准访问。

致谢

我们感谢 Daniel Fett、Sebastian Ebling、Dave Tonge、Mike Jones、Nat Sakimura 和 Rob Otto 在本 规范编写期间提供的宝贵反馈。

我们还感谢 Vladimir Dzhuvinov、 Takahiko Kawasaki、Daniel Fett、 Dave Tonge、Travis Spencer、 Joergen Binningsboe、Aamund Bremer、 Steinar Noem、Francis Pouatcha、 Jacob Ideskog、Hannes Tschofenig 和 Aaron Parecki 对本规范提供的宝贵 反馈。

作者地址

Torsten Lodderstedt
yes.com
Justin Richer
Bespoke Engineering
Brian Campbell
Ping Identity