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_informationpayment_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 中属于客户的 contactsphotos 同时拥有 readwrite 访问权限。 如果该请求被授予,客户端 会认为它能够使用 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 特定字段。第一个 访问请求包含此处指定的 actionslocationsdatatypes 字段,以及 API 特定的 geolocation 字段,表示访问在给定坐标拍摄的照片。 第二个访问请求包含此处指定的 actionsidentifier 字段,以及 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] 来 改进流程的安全性、隐私性和可靠性。详见第 121311.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"
   }
]
图 9URL 解码后的 "authorization_details"

3.1. 与 "scope" 参数的关系

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

本规范支持 authorization_detailsscope 的组合使用, 部分原因是允许现有基于 OAuth 的应用逐步迁移到 专门使用 authorization_detailsRECOMMENDED 某个给定 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_coderefresh_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 类型所使用的每个字段都包含累加权限, actionslocations 数组内的每个值 都指定不同的访问元素。为了在此 实例中进行比较,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 值涵盖了 此前授予客户端的 readwrite 访问的任何方面。 请注意,其他 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 MAYauthorization_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 在其响应中包含该令牌的授权详情信息, 则该信息 MUSTauthorization_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_coderefresh_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 FettSebastian EblingDave TongeMike JonesNat SakimuraRob Otto 在本 规范编写期间提供的宝贵反馈。

我们还感谢 Vladimir DzhuvinovTakahiko KawasakiDaniel FettDave TongeTravis SpencerJoergen BinningsboeAamund BremerSteinar NoemFrancis PouatchaJacob IdeskogHannes TschofenigAaron Parecki 对本规范提供的宝贵 反馈。

作者地址

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