Facebook OAuth 2.0“代码”和“令牌”

为什么在 Facebook OAuth2身份验证流程中同时需要“代码”和“令牌”,如下所述: https://developers.facebook.com/docs/authentication/

如果查看 OAuth 对话框引用(https://developers.facebook.com/docs/reference/dialogs/oauth/) ,似乎您只使用令牌获取用户的信息,如果将 response_type参数指定为 tokencode,token,那么您将在第一次获取令牌。

为什么需要获取“代码”,然后使用该代码获取“令牌”,而不是直接获取令牌?

我想我误解了 OAuth 工作原理的一些基本内容,但是如果您在第一次使用对话框时获得令牌,那么您似乎可以完全避免对 https://graph.facebook.com/oauth/access_token的请求。

42152 次浏览

当用户登录时,您将收到一个令牌。但是在执行其他操作时,可能需要更改标记。EG 作为你的应用程序/页面发布,或者作为用户使用 offline_access发布。

来自 OAuth 2.0规范:

授权代码提供了一些重要的安全优势 例如认证客户端的能力,以及传输 将访问令牌直接传递给客户端,而不将其传递给客户端 资源所有者的用户代理,可能将其暴露给其他人, 包括资源所有者。

因此,基本上-主要原因是限制参与者获取访问令牌的 # 。

“令牌”响应主要针对浏览器中的客户端(例如: JavaScript 客户端)。

无耻地从 Salesforce 文档借来:

授权码

授权代码是表示用户的访问授权的 短命的纪念品,由授权服务器创建,并通过浏览器传递给客户端应用程序。客户端应用程序将授权代码发送到授权服务器,以获取访问令牌(可选)和刷新令牌。

访问令牌 客户端使用访问令牌代表最终用户发出经过身份验证的请求。它具有比授权代码更高的 更长的寿命,通常以分钟或小时为单位。当访问令牌过期时,尝试使用它将失败,并且必须通过刷新令牌获得新的访问令牌。

基本上,作为 Lix 的回答的扩展,访问代码路由允许资源所有者(即 Facebook 用户)撤销对其用户代理(即浏览器)的授权,例如通过注销,而不撤销对脱机客户端(即您的应用程序)的授权。 如果这不重要,那么就不需要使用访问代码路由。

此外,提供访问代码是为了确保提供给服务器的令牌实际上是注册给资源所有者(即 Facebook 用户) ,而不是用户代理(或中间人)。

这似乎类似于选择隐式与授权代码授权流的问题。

还有,作为 德鲁提到过,

当访问令牌过期时,尝试使用它将失败,并且必须通过刷新令牌获得新的访问令牌。

另一部分是刷新令牌,但我不认为这在 FB 文档中有很好的解释。如果我是正确的,隐式授权(直接令牌)应该是真正短暂的,但这是要强制执行的,FB.js 似乎隐藏了很多(这一点我没有深入研究)。

如果我是正确的,code%20token是一种优化,允许用户代理拥有令牌,并允许服务器在单个请求中启动令牌交换过程(因为任何超过网络 IO 的操作都被认为是昂贵的,特别是对用户代理而言)。

由于用户 而不是客户端应用程序针对授权服务器进行身份验证(即 facebook) ,出现了混淆。 保护客户端应用程序(使用 https)、用户代理(浏览器)的安全非常简单。

以下是 IETF-oauth (https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-threatmodel-08#section-3.4)的原始配方:

3.4授权码

授权代码表示 成功的最终用户授权程序,并由客户端使用 获取访问和刷新令牌。授权代码被发送到 客户端的重定向 URI 而不是令牌有两个目的。

  1. 基于浏览器的流向潜在用户暴露协议参数 通过 URI 查询参数(HTTP 参考) ,浏览器 缓存,或者日志文件条目,并且可以重播 减少这种威胁,短命的授权代码通过 代替令牌,并通过更安全的 客户端与授权服务器之间的直接连接。

  2. 在直接过程中对客户端进行身份验证要简单得多 客户端和授权服务器之间的请求 间接授权请求的上下文 需要数字签名。

让我们以一个简单的示例来区分身份验证代码和访问令牌。

作为一个用户,你想尝试一个新的 Facebook 应用程序叫做 Highjack。 所以你点击应用程序,Highjack 应用程序会要求你登录你的 Facebook 账户。当你完成后,Facebook 会为你生成一个认证代码。

然后这些代码被传递给 Highjack 服务器,后者使用自己的 FB 客户端 ID、 FB 机密和您的身份验证代码来获得访问令牌。

在上面的例子中,身份验证代码确认您是一个有效的 FB 用户。但是第二个步骤是“作为一个 FB 用户,你可以为某些资源提供访问 Highjack 应用程序的权限”。

如果 Highjack 应用程序需要隐式授权(即直接访问令牌) ,那么访问令牌对您也是可见的,因为它正在与浏览器交换。这意味着您现在可以使用访问令牌代表 Highjack 调用所有 Facebook API。(你只能使用访问令牌获取个人信息,但 Facebook 无法知道是谁在调用他们的 API。)

因为我们有两个方面(你和海杰克)与 Facebook 认证,我们有这个双重机制。

如果你看一下 授权代码 OAuth 类型的流,是的,精算师有两个步骤:

  1. <user_session_id, client_id> => authorization_code
  2. <client_id, redirect_uri, authorization_code, client_secret> => access_token, refresh_token

在步骤1: 用户告诉 OAuth 服务器“我想授权这个客户端(client_id)访问我的资源。这是我的认证(user_session_id或其他)”

在步骤2中: 客户机(client_id)告诉 OAuth 服务器“我已经获得了用户的授权(authorization_code) ,请给我一个访问令牌,以便以后访问。这是我的认证(client_id & client_secret)”

您看,如果我们省略了步骤2,那么就不能保证客户端身份验证。任何客户机都可以使用不同的 client_id调用第1步,并获得该 client_id的访问令牌,而不是它自己的。所以我们需要第二步。

如果你真的想把第1步和第2步结合起来,你可以这样做:

<client_id, redirect_uri, client_secret> => access_token, refresh_token

我们在开放 API 平台中使用这种方法,目前还没有发现任何安全问题。

顺便说一下,实际上有一个 隐式授予类型,即:

<client_id, redirect_uri> => access_token, refresh_token

它通常适用于没有服务器后端的仅客户端应用程序。在这种情况下,OAuth 服务器必须确保重定向 URI 属于该客户机(例如,与寄存器 redirect_uri相同)。

这是因为访问令牌是使用只有 FB 和客户端知道的共享秘密授予 AUTHENTICATION 客户端(第三方应用程序)的。用户可以直接请求访问令牌的唯一方法是知道共享的秘密,这将使秘密公开,并可能导致中间人攻击。此外,虽然 FB 可以保证到用户的安全连接,但是 FB 不能保证到客户端的令牌切换是安全的。但是,FB (和 OAuth2)确实需要客户端和 FB 之间的安全连接。访问令牌绑定到客户机公共 ID (通常是散列的) ,这意味着只有原始客户机应用程序可以使用它来请求令牌,因为秘密与授权代码一起发送以获取访问令牌。

答: 您需要/希望同时使用代码和令牌以获得额外的安全性。

根据 Nate Barbettini 的说法,我们需要额外的步骤来交换访问令牌的身份验证代码,因为身份验证代码可以在前端通道使用(不太安全) ,而访问令牌可以在后端通道使用(更安全)。

因此,安全的好处是访问令牌不会暴露给浏览器,因此不能从浏览器中截获/抓取。我们更信任 Web 服务器,它通过后台通道进行通信。访问令牌是保密的,可以保留在 Web 服务器上,而不会暴露给浏览器(即前端通道)。

欲了解更多信息,请观看下面这段精彩的视频:

OAuth 2.0和 OpenID Connect (英文) Https://youtu.be/996oiexhze0?t=26m30s (开始26分钟)

理论上讲,

  • Access Tokens 不能告诉我们用户是否已经身份验证,但是身份验证代码可以。
  • 不应该使用 Auth 代码 来访问 API,但应该使用访问令牌。

如果您有一个单页应用程序或移动应用程序,没有或最低限度的后端,您的应用程序可能希望访问用户的 FB 数据直接在前端。因此提供了访问令牌。

在另一种情况下,你可能希望用户使用 Facebook、 Google 等外部认证服务提供商注册/登录你的应用程序。在这种情况下,您的前端将把身份验证代码发送到后端,后端可用于从服务器端的 Facebook 获取访问令牌。现在您的服务器可以从服务器访问用户的 FB 数据了。

enter image description here

在 OAuth 2.0 with facebook 中,总体概念如下所示。

步骤1。通过 GET 请求获取“授权代码”

request URI: https://www.facebook.com/dialog/oauth
Params:
response_type=code
client_id={add your "App id" got by registering app}
redirect_uri={add redirect uri defined at the registration of app}
scope={add the scope needed in your app}
Headers: None

步骤2。通过以 POST 请求的形式发送授权代码来获取“ Access Token”

    URI: https://graph.facebook.com/oauth/access_token
Params:
grant_type=authorization_code
client_id=<add your "App id" got by registering app>
redirect_uri=<add redirect uri defined at the registration of app>
code=<obtained authorization code from previous step>
Headers:
Authorization:Basic encode <App Id:App Secret> with base64
Content-Type:application/json

步骤3。使用从上一步获得的访问令牌并检索用户资源