无需资源所有者同意生成访问令牌的OAuth流程如何实现?
本问题使用的角色和术语与RFC 6749定义一致。
用例描述
我希望允许受信任的OAuth client 向 authorization server 发起请求,无需 resource owner 同意(且流程不涉及资源所有者或其代理),即可代表其签发 access token。
调研结果
据我所知,RFC 6749 第4节中没有匹配该流程的授权类型:
| 授权类型 | 是否适用 | 原因 |
|---|---|---|
| Authorization Code Grant RFC 6749 第4.1节 | 否 | 需要同时涉及 Resource Owner 和 User-Agent。 |
| Implicit Grant RFC 6749 第4.2节 | 否 | 同样需要同时涉及 Resource Owner 和 User-Agent。 |
| Resource Owner Password Credentials Grant RFC 6749 第4.3节 | 否 | 仅当知晓资源所有者密码时可用,但我们不掌握该密码。 |
| Client Credentials Grant RFC 6749 第4.4节 | 部分适用 | 不涉及 Resource Owner 或其 User-Agent,但无法代表用户授予访问权限。 |
| Token Exchange RFC 8693 第2节 | 部分适用 | 需要初始令牌(即subject_token),但本场景不存在该令牌。 |
Client Credentials授权类型
Client Credentials 授权类型具有可行性,因为它允许 client 无需资源所有者参与即可访问其持有的受保护资源。但据我理解,该模式无法代表 resource owner 申请权限。引用 RFC 6749 第4.4节 内容:
当客户端请求访问其控制的受保护资源,或已与授权服务器预先约定的其他资源所有者的受保护资源时,客户端可仅使用自身客户端凭证申请访问令牌(...)。
因此,通过 Client Credentials 授权类型返回的访问令牌,无法赋值 RFC 7662 第2.2节:OAuth 2.0令牌自省 > 自省响应(参考 RFC 7519 第4.1.2节:JWT)中定义的 sub 声明值。
Token Exchange授权类型
该授权类型由@Kaankom提出
RFC 8693定义了通过模拟和委托方式获取安全令牌的方法,看起来完全适配本用例,但该授权类型要求传入subject_token参数,该参数“代表执行操作方的身份”。RFC中说明:
通常,该实体为被授权使用所申请的安全令牌、代表主体执行操作的一方。
我没有该令牌,但我可以自行生成一个新令牌(见解决方案5)。
非标准解决方案
解决方案1:新增OAuth授权类型
RFC 6749 第4.5节允许实现自定义授权类型。与 Client Credentials 类似,该全新授权类型的 Access Token Request 需要新增一个参数,用于指定 client 将要代表的 resource owner 的标识符。
解决方案2:调整 Client Credentials 授权类型
无需实现新的OAuth授权类型(参考解决方案1),我们可以在现有 Client Credentials 授权类型中新增一个可选参数。如果该参数被传入,authorization server 需要校验该 client 是否有权限代表参数指定的 resource owner 执行操作。
解决方案3:调整 Authorization Code 授权类型
使用 Authorization Code 授权类型时,我们可以跳过 RFC 6749 第4.1节定义的A、B、C步骤,允许 client 无需传入code或redirect_uri,仅通过自身客户端凭证外加指定 resource owner 的额外参数即可申请访问令牌。
解决方案4:在OAuth体系外实现
浏览互联网可以找到绕过OAuth机制及access_token的实现方案。例如文章《如何从APIKey迁移到OAuth 2.0 Client Credentials》中,在调用 resource server 时使用了额外的HTTP头Acting-For。
解决方案5:搭配自行生成令牌的 Token Exchange 授权类型
Token Exchange 授权类型需要subject_token,但据我所知,RFC并未定义 authorization server 基于该令牌应当执行的校验策略。因此理论上 client 可以自行生成携带目标 subject(sub声明)的未签名JWT,以此换取签名后的JWT。该方案看起来可行,但需要进一步调研。
注意事项
我有意没有指定解决方案1、2、3中使用的参数名称。不过 OpenID Connect Core 1.0 第3.1.2.1节/第4节定义了名为login_hint的可选参数,作用是“向授权服务器提示终端用户可能使用的登录标识”。另外sub也是一个不错的备选参数名。
内容的提问来源于stack exchange,提问作者Raphael Medaer

