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

Posted

技术标签:

【中文标题】Facebook OAuth 2.0“代码”和“令牌”【英文标题】:Facebook OAuth 2.0 "code" and "token" 【发布时间】:2012-01-29 18:43:39 【问题描述】:

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

如果您查看 OAuth 对话框参考 (https://developers.facebook.com/docs/reference/dialogs/oauth/),您似乎只使用令牌来获取有关用户的信息,并且如果您将 response_type 参数指定为 tokencode,token ,那么你就第一时间拿到了token。

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

我想我误解了有关 OAuth 工作原理的一些基本知识,但如果您第一次通过对话框获得令牌,您似乎完全避免了对 https://graph.facebook.com/oauth/access_token 的请求。

【问题讨论】:

What is the difference between the 2 workflows? When to use Authorization Code flow?的可能重复 【参考方案1】:

如果你看flow of Authorization Code OAuth type,是的,精算有两个步骤:

    <user_session_id, client_id> => authorization_code <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),请给我一个访问令牌以供以后访问。这是我的身份验证 (@ 987654329@ & client_secret)"

您会看到,如果我们省略第 2 步,则无法保证客户端身份验证。任何客户端都可以使用不同的client_id 调用 step1 并获取该client_id 的访问令牌,而不是自己的。这就是我们需要 step2 的原因。

如果你真的想把 step1 和 step2 结合起来,你可以这样做:

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

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

BTW,其实还有一个Implicit Grant type,就是:

<client_id, redirect_uri> => access_token, refresh_token

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

【讨论】:

【参考方案2】:

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

作为用户,您想尝试一款名为 Highjack 的新 Facebook 应用。 因此,您单击该应用程序,Highjack 应用程序会要求您登录您的 Facebook 帐户。完成后,Facebook 会为您生成一个验证码。

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

在上面的示例中,身份验证代码确认您作为用户是有效的 FB 用户。但是第二步说“您作为 FB 用户正在授予对某些资源的 Highjack 应用程序的访问权限”。

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

由于我们有 2 方(您和 Highjack)使用 Facebook 进行身份验证,因此我们有这种 2 折机制。

【讨论】:

一个非常简洁的描述! 您是否有一个真实的场景,即 Highjack 不希望用户代表它调用 Facebook api?对于一个简单的“使用 Facebook 登录”用例,两种方式都可以,因为 Highack 的服务器只需要来自用户的令牌来检查它是否有效并获取用户的 Facebook id(在数据库中找到它)。在这种情况下,令牌是否也在用户手中并不重要(此令牌的唯一权限是询问“用户的 Facebook id 是什么?”)。对吗? 对这个解释有一个澄清以避免误解。 此 OAuth2 流程由两个步骤组成,不是为了将用户身份验证和客户端授权分开,而是出于安全原因。 这是将这两个步骤(授权码获取和访问令牌获取)分开的最重要原因。请看下面来自“Michael R”的答案以及 Nate Barbettini 的精彩视频。 @Oren 当第三方想要查看用户分析,即某人在社交刀片上查看其他分析时,社交刀片需要访问所述用户分析并且用户不在身边为他们提供访问令牌,因此社交刀片获取长期令牌以换取用户的短期令牌并存储在他们的数据库中,因此社交刀片可以随时访问,而无需用户登录 Facebook 并授予他们访问权限(我猜这就是它的工作原理) 对不起,这个答案不是很完整。它没有提到迈克尔 R 的回答中的视频中提到的“前通道”和“后通道”之间的重要安全区别。【参考方案3】:

在带有 facebook 的 OAuth 2.0 中,总体概念如下。

Step 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

Step 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

Step 3. 使用上述步骤获取的访问令牌并检索用户资源

【讨论】:

【参考方案4】:

理论上,

访问令牌无法告诉我们用户是否已通过身份验证,但身份验证代码可以。 授权码不应用于获取 API 的访问权限,但应使用访问令牌。

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

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

【讨论】:

图片来源是什么?【参考方案5】:

Answer)您需要/想要代码和令牌以获得额外的安全性。

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

因此,安全优势在于访问令牌不会暴露给浏览器,因此无法从浏览器中拦截/获取。我们更信任网络服务器,它通过反向渠道进行通信。访问令牌是秘密的,然后可以保留在 Web 服务器上,并且不会暴露给浏览器(即前端通道)。

有关更多信息,请观看这​​段精彩的视频:

OAuth 2.0 和 OpenID Connect(简单英语) https://youtu.be/996OiexHze0?t=26m30s(开始 26 分钟)

【讨论】:

这是唯一有用的主题答案。 我不明白这部分。客户端交换访问令牌的授权代码,而不向资源所有者用户代理透露令牌。同意。但是用户代理如何在没有访问令牌的情况下请求资源。无论如何,用户代理会知道访问令牌的权利吗? 客户端和资源所有者将有不同的令牌被维护?例如,我在 *** 中使用 facebook 登录。 SO 后端将根据我的同意获取访问令牌,并且我和 SO 之间的通信将使用不同的方案/令牌 @SundarRajan,这是我的理解:用户代理通过自己的后端请求资源,后端充当代理。这样,用户代理实际上不必知道访问令牌。但是,应用程序后端必须在为其请求资源之前对用户代理进行身份验证。【参考方案6】:

这是因为访问令牌是使用只有 FB 和客户端知道的共享密钥提供给 AUTHENTICATED 客户端(第三方应用程序)的。用户可以直接请求访问令牌的唯一方法是知道共享秘密,这将使秘密公开并可能导致中间人攻击。此外,虽然 FB 可以保证与用户的安全连接,但 FB 不能保证将令牌传递给客户端是安全的。但是,FB(和 OAuth2)确实需要客户端和 FB 之间的安全连接。访问令牌与客户端公共 ID(通常经过哈希处理)相关联,这意味着只有原始客户端应用程序才能使用它来请求令牌,因为密钥与授权代码一起发送以获取访问令牌。

【讨论】:

【参考方案7】:

混淆是因为用户代表他自己而不是客户端应用程序对授权服务器进行身份验证(即 facebook)。 保护客户端应用程序(使用 https)然后保护用户代理(浏览器)非常简单。

这是来自 IETF-oauth (https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-threatmodel-08#section-3.4) 的原始表述:

3.4。授权码

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

    基于浏览器的流将协议参数暴露给潜在的 攻击者通过 URI 查询参数(HTTP 引荐来源网址)、浏览器 缓存或日志文件条目,并且可以重播。为了 减少这种威胁,通过短暂的授权码 而不是令牌并通过更安全的方式交换令牌 客户端和授权服务器之间的直接连接。

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

【讨论】:

【参考方案8】:

基本上,作为Lix's answer 的扩展,访问代码路由允许资源所有者(即 Facebook 用户)撤销对其用户代理(即他们的浏览器)的授权,例如通过注销,而不撤销对离线客户端(即您的应用程序)的授权。 如果这不重要,则无需使用访问代码路由。

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

这似乎类似于选择隐式与授权代码授予流程的问题。 In fact, here is what looks like an opposite view point?!.

另外,作为Drew mentioned,

访问令牌过期后,尝试使用会失败,必须通过刷新令牌获取新的访问令牌。

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

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

【讨论】:

【参考方案9】:

无耻借用Salesforce Documentation:

授权码

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

访问令牌 客户端使用访问令牌代表最终用户发出经过身份验证的请求。它比授权代码具有更长的生命周期,通常为几分钟或几小时。当访问令牌过期时,尝试使用它会失败,必须通过刷新令牌获取新的访问令牌。

【讨论】:

为什么同时使用?各有什么优势?仅仅是因为有生之年吗?请您稍微扩展一下这个答案,因为它并没有真正回答 OP。 @Anoyz,他们有不同的目的。 Web应用程序需要Authorization Code从授权服务器获取Access Token,它需要Access Token来代表他们对用户资源的访问进行认证。 复制官网的定义是没有意义的。请说明为什么我们需要授权码来获取访问令牌而不是直接获取访问令牌。 在下面查看我的回答,希望对您有所帮助。 @arganzheng 因为如果我们只有一个令牌,这意味着如果有人截获了该令牌,那么他们可以随时随地使用它。但是,当将短期令牌传递给客户端时,客户端随后将使用客户端 id 和客户端机密来传递短期令牌以进行授权,然后才将正确的访问令牌返回给客户端。可以将其视为进入 1 把锁的 2 把钥匙。【参考方案10】:

来自OAuth 2.0 Spec:

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

所以,基本上 - 主要原因是限制获得访问令牌的参与者的数量。

“token”响应主要用于浏览器中的客户端(例如:javascript 客户端)。

【讨论】:

只是为了限制演员的数量??和保护博览会??增加的复杂性真的有意义吗? 那和客户端认证。更多背景:tools.ietf.org/html/… 该代码是一种不将 app_secret 写入 JS 客户端的方法。客户端请求代码,将代码发送到请求令牌的 API。将令牌存储在本地并将您的 app_secret 保存到服务器端。远离攻击者。这是安全的又一步。 这并不能回答你为什么要使用response_type: 'code token'【参考方案11】:

当用户登录时,您会收到一个令牌。但您可能希望在执行其他操作时更改该令牌。 EG 作为您的应用/页面发布或以offline_access 的用户身份发布。

【讨论】:

如果你第一次要求你需要的权限,你不能用同一个token吗?如果你有offline_access,那么你可以保存令牌。我仍然对为什么流程中需要代码感到困惑...... 您当然可以使用相同的令牌 - 但普通令牌会在一段时间后过期。 TBH 我从来没有手动使用过那个“代码”参数——我所有的登录都是通过从 SDK 中检索 loginURL 来完成的...... 我认为目前仅在 php sdk 上。在最新的 oauth2 身份验证文档中,如果您想做 php 服务器端以外的任何事情,则需要使用“代码”

以上是关于Facebook OAuth 2.0“代码”和“令牌”的主要内容,如果未能解决你的问题,请参考以下文章

使用 facebook 登录并使用 oauth 2.0 对 REST api 调用进行身份验证

Facebook Oauth 2.0 访问令牌会过期吗?

如何在服务器端完全启用 Facebook OAuth 2.0?

Android中LinkedIn的Oauth 2.0授权

春天。 REST API 的实现 Oauth.2.0

10 分钟理解什么是 OAuth 2.0 协议