如何使用资源所有者凭据授权验证 public 客户端的范围
How to validate scopes for public client using resource owner credentials grant
鉴于 public Javascript 客户端想要使用资源所有者密码凭据授予类型访问 API 端点的情况。
典型的请求如下所示:
username = "john.doe@mail.com"
password = "MyP@assw0rd!"
grant_type = "password"
scope = "openid offline_access"
没有传递 client_id
,因为客户端无法存储 client_secret
,根据 Resource Owner Password Credentials Grant 规范,它可以被省略。
The authorization server MUST:
- require client authentication for confidential clients or for any
client that was issued client credentials (or with other
authentication requirements)
问题是如果客户端未知,scope = "openid offline_access"
参数无法验证。在我的理解中,范围是为描述应用程序权限而设计的。
马上就有问题了
如何在省略 client_id
时验证客户端范围(有意且按规范)?
一些推理:
省略client_id
的原因是因为任何人都可以轻松地从 JS 客户端检索它并利用它。
这种情况下的 CORS 验证几乎增加了零值,因为主机 header 可以手动制作。
TL;DR 跳转到下面的 结论 部分...
Javascript 上存储的 client_id
确实可以很容易地检索到,但是这个标识符不是秘密,规范中明确提到了这一点。
The client identifier is not a secret; it is exposed to the resource owner and MUST NOT be used alone for client authentication.
这意味着 在您的 public 客户端 上使用 client_id
是可以接受的,所以现在让我们关注第二个问题...客户端身份验证.
您引用的部分说,机密客户端或任何已颁发凭据的客户端必须要求客户端身份验证。您的应用程序不属于上述任何一种情况,因此 客户端身份验证要求不适用。
好的,所以您的客户端不需要(实际上也不能执行)客户端身份验证。这会导致您的场景出现问题,因为您想要验证请求的范围,所以让我们尝试找到一个合规的解决方案...
首先是找到一种方法将 client_id
传递给服务器,因为这是必需的。如果客户端是机密的,这将在 Authorization
header 中与其秘密一起传递,但我们不在那种情况下。但是,规范允许省略 client_secret
,因此我们仍然使用 HTTP header 来传递客户端标识符。
client_secret: REQUIRED. The client secret. The client MAY omit the parameter if the client secret is an empty string.
现在,我们在服务器端有 client_id
,但我们不能相信它,不是根据规范,因为正如我们已经提到的,我们不能单独使用这个标识符客户端身份验证,即使我们尝试了一些聪明的(也就是很容易在不知情的情况下弄错)身份验证机制,还有:
The authorization server MAY establish a client authentication method
with public clients. However, the authorization server MUST NOT rely
on public client authentication for the purpose of identifying the
client.
妈的,这下没戏了! 我无法验证,所以我不能信任客户端身份,所以我无法验证范围。
我听到了,但仍有一些希望。现在让我们关注规范的另一部分。
When client authentication is not possible, the authorization server SHOULD employ other means to validate the client's identity -- for example, by requiring the registration of the client redirection URI or enlisting the resource owner to confirm identity.
JACKPOT!你确实在客户端身份确认过程中招募了资源所有者,他妈的他把用户名和密码给了客户端,这样就解决了。
结论
您似乎确实有办法完成手头的任务,并且仍然声称符合规范(至少从 OAuth 2.0 方面来看)。唯一要做的就是这只是我的意见,所以我还想给你一个资源所有者端点的实际实现的例子。
如果您转到 Auth0 Authentication API - Resource Owner Endpoint,您会找到具体的实现。看到别人如何处理这个问题总是好的。我已经注意到这个实现选择允许 client_id
请求 body 本身并且有一些其他自定义参数作为选项,但这很好,因为 OAuth 2.0 没有定义严格的协议,只是定义基础。
我想提请您注意的最后一件事是,offline_access
范围在 OpenID Connect 中用于表示您需要刷新令牌,但您不应该为 [=85= 】 客户。存储刷新令牌(通常是 long-lived 凭证)几乎与存储实际密码一样糟糕。有关此类令牌的一些一般指导,请参阅 refresh tokens。
在这种流程中可以针对每个客户端验证范围的建议是不正确的。由于 client_id
是非机密标识符,因此它没有任何价值。任何人都可以从您的 Javascript 实现中获取它并冒充客户端,对用户凭据进行网络钓鱼。因此,请求的范围只能以通用的、非客户端特定的方式处理,而且:
OAuth 2.0 规范建议不要在这种情况下使用资源所有者密码凭证流程,https://www.rfc-editor.org/rfc/rfc6749#section-1.3.3:
The credentials should only be used when there is a high degree of
trust between the resource owner and the client (e.g., the client
is part of the device operating system or a highly privileged
application), and when other authorization grant types are not
available (such as an authorization code).
在浏览器内 Javascript 的情况下,资源所有者和客户端之间不能高度信任,因为无法可靠地识别客户端。
鉴于 public Javascript 客户端想要使用资源所有者密码凭据授予类型访问 API 端点的情况。
典型的请求如下所示:
username = "john.doe@mail.com"
password = "MyP@assw0rd!"
grant_type = "password"
scope = "openid offline_access"
没有传递 client_id
,因为客户端无法存储 client_secret
,根据 Resource Owner Password Credentials Grant 规范,它可以被省略。
The authorization server MUST:
- require client authentication for confidential clients or for any client that was issued client credentials (or with other authentication requirements)
问题是如果客户端未知,scope = "openid offline_access"
参数无法验证。在我的理解中,范围是为描述应用程序权限而设计的。
马上就有问题了
如何在省略 client_id
时验证客户端范围(有意且按规范)?
一些推理:
省略
client_id
的原因是因为任何人都可以轻松地从 JS 客户端检索它并利用它。这种情况下的 CORS 验证几乎增加了零值,因为主机 header 可以手动制作。
TL;DR 跳转到下面的 结论 部分...
Javascript 上存储的 client_id
确实可以很容易地检索到,但是这个标识符不是秘密,规范中明确提到了这一点。
The client identifier is not a secret; it is exposed to the resource owner and MUST NOT be used alone for client authentication.
这意味着 在您的 public 客户端 上使用 client_id
是可以接受的,所以现在让我们关注第二个问题...客户端身份验证.
您引用的部分说,机密客户端或任何已颁发凭据的客户端必须要求客户端身份验证。您的应用程序不属于上述任何一种情况,因此 客户端身份验证要求不适用。
好的,所以您的客户端不需要(实际上也不能执行)客户端身份验证。这会导致您的场景出现问题,因为您想要验证请求的范围,所以让我们尝试找到一个合规的解决方案...
首先是找到一种方法将 client_id
传递给服务器,因为这是必需的。如果客户端是机密的,这将在 Authorization
header 中与其秘密一起传递,但我们不在那种情况下。但是,规范允许省略 client_secret
,因此我们仍然使用 HTTP header 来传递客户端标识符。
client_secret: REQUIRED. The client secret. The client MAY omit the parameter if the client secret is an empty string.
现在,我们在服务器端有 client_id
,但我们不能相信它,不是根据规范,因为正如我们已经提到的,我们不能单独使用这个标识符客户端身份验证,即使我们尝试了一些聪明的(也就是很容易在不知情的情况下弄错)身份验证机制,还有:
The authorization server MAY establish a client authentication method with public clients. However, the authorization server MUST NOT rely on public client authentication for the purpose of identifying the client.
妈的,这下没戏了! 我无法验证,所以我不能信任客户端身份,所以我无法验证范围。
我听到了,但仍有一些希望。现在让我们关注规范的另一部分。
When client authentication is not possible, the authorization server SHOULD employ other means to validate the client's identity -- for example, by requiring the registration of the client redirection URI or enlisting the resource owner to confirm identity.
JACKPOT!你确实在客户端身份确认过程中招募了资源所有者,他妈的他把用户名和密码给了客户端,这样就解决了。
结论
您似乎确实有办法完成手头的任务,并且仍然声称符合规范(至少从 OAuth 2.0 方面来看)。唯一要做的就是这只是我的意见,所以我还想给你一个资源所有者端点的实际实现的例子。
如果您转到 Auth0 Authentication API - Resource Owner Endpoint,您会找到具体的实现。看到别人如何处理这个问题总是好的。我已经注意到这个实现选择允许 client_id
请求 body 本身并且有一些其他自定义参数作为选项,但这很好,因为 OAuth 2.0 没有定义严格的协议,只是定义基础。
我想提请您注意的最后一件事是,offline_access
范围在 OpenID Connect 中用于表示您需要刷新令牌,但您不应该为 [=85= 】 客户。存储刷新令牌(通常是 long-lived 凭证)几乎与存储实际密码一样糟糕。有关此类令牌的一些一般指导,请参阅 refresh tokens。
在这种流程中可以针对每个客户端验证范围的建议是不正确的。由于 client_id
是非机密标识符,因此它没有任何价值。任何人都可以从您的 Javascript 实现中获取它并冒充客户端,对用户凭据进行网络钓鱼。因此,请求的范围只能以通用的、非客户端特定的方式处理,而且:
OAuth 2.0 规范建议不要在这种情况下使用资源所有者密码凭证流程,https://www.rfc-editor.org/rfc/rfc6749#section-1.3.3:
The credentials should only be used when there is a high degree of trust between the resource owner and the client (e.g., the client is part of the device operating system or a highly privileged
application), and when other authorization grant types are not
available (such as an authorization code).
在浏览器内 Javascript 的情况下,资源所有者和客户端之间不能高度信任,因为无法可靠地识别客户端。