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


69

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

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

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

我猜我对OAuth的工作原理有一些误解,但是https://graph.facebook.com/oauth/access_token如果您第一次在对话框中获得令牌,似乎可以完全避免请求。


Answers:


47

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

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

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

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

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

由于我们有2个参与方(您和Highjack)通过Facebook进行身份验证,因此我们有2种折叠机制。


一个非常干净的描述!
维克多

您是否有一个现实世界场景,即Highjack不想让用户代表它调用Facebook api?对于简单的“使用Facebook登录”用例,两种方法都可以,因为Highack的服务器只需要来自用户的令牌即可检查它是否有效并获取用户的Facebook ID(在数据库中找到它)。在这种情况下,令牌是否也位于用户手中都没有关系(此令牌具有的唯一权限是询问“用户的Facebook ID是什么?”)。对?
奥伦

为了避免误解,对此解释进行了澄清。 这个OAuth2流程包括两个步骤,不是出于安全原因,而是将用户身份验证和客户端授权分开。这是区分这两个步骤(获取身份验证代码和获取访问令牌)的最重要原因。请收看Nate Barbettini的精彩视频,看看下面来自“ Michael R”的答案。
Klyuch

@Oren,当第三方希望查看用户分析时,即某人正在使用社交刀片查看其他分析时,社交刀片需要访问所述用户分析,并且用户无处不在为他们提供访问令牌,因此,使用寿命长的令牌是由社交刀片所获得,以换取用户的较早令牌并存储在他们的数据库中,因此社交刀片可以随时访问,而无需用户登录到Facebook并提供访问权限(我猜这就是它的工作方式)
Tim Dowd

29

无耻地从Salesforce文档中借来的:

授权码

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

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


37
为什么两者同时使用?每个都有什么优势?仅仅是因为一生吗?您能否扩展一下这个答案,因为它并不能真正回答OP。
Anoyz 2014年

1
@Anoyz,他们有不同的目的。Web应用程序需要从授权服务器访问令牌获得授权代码,并且需要访问令牌来代表用户验证对用户资源的访问。
阿列克谢2015年

9
只是从官方网站复制定义完全没有意义。请说明为什么我们需要一个授权码来获取访问令牌而不是直接获取访问令牌的原因。
arganzheng '16

请在下面查看我的答案,希望对您有所帮助。
arganzheng '16

@arganzheng,因为如果我们只拥有一个令牌,这意味着如果有人拦截了该令牌,那么他们可以随时随地使用它。但是,当将短期令牌传递给客户端时,客户端随后会将短期令牌传递给客户端ID和客户端密钥以进行授权,只有这样,正确的访问令牌才会返回给客户端。可以将其视为进入1个锁的2把钥匙。
Tim Dowd

22

根据OAuth 2.0规范

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

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

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


1
只是为了限制演员人数?和博览会的保护??增加的复杂性真的有意义吗?
Jaime Hablutzel

1
那和客户端认证。更多的背景:tools.ietf.org/html/...
斯科特T.

5
该代码是不将app_secret写入JS客户端的一种方法。客户端请求代码,然后将代码发送到请求令牌的API。将令牌存储在本地,并将app_secret保留在服务器端。远离攻击者。这是安全性的又一步。
RafaelTSCS

这没有回答您为什么要使用的问题response_type: 'code token'
mcabral

9

如果查看授权码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调用step1,并获得该client_id而不是其自己的访问令牌。这就是为什么我们需要step2。

如果您确实要结合步骤1和步骤2,则可以执行以下操作:

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

我们在Open Api平台中使用了这种方法,但尚未发现任何安全问题。

顺便说一句,实际上存在一个隐式授予类型,即:

<client_id, redirect_uri> => access_token, refresh_token

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


7

之所以出现混淆,是因为用户代表自己而不是客户端应用通过授权服务器(即,facebook)进行身份验证。保护客户端应用程序(使用https)和用户代理(浏览器)非常简单。

这是IETF-oauth的原始公式(http://tools.ietf.org/html/draft-ietf-oauth-v2-threatmodel-08#section-3.4):

3.4。授权码

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

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

  2. 与间接授权请求相比,在客户端和授权服务器之间的直接请求期间对客户端进行身份验证要简单得多。后者将需要数字签名。


5

答案)您需要/需要代码和令牌以提高安全性。

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

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

有关更多信息,请观看以下精彩视频:

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


2
这是唯一有用的主题答案。
阿德里安

我不明白这部分。客户端交换访问令牌的授权代码,而不将令牌透露给资源所有者用户代理。同意 但是用户代理如何可以在没有访问令牌的情况下请求资源。无论如何,用户代理会知道访问令牌正确吗?
Sundar Rajan

客户端和资源所有者将维护不同的令牌吗?例如,我已经在Stackoverflow中用Facebook登录。SO后端将根据我的同意获得访问令牌,而我与SO之间的通信将采用不同的方案/令牌
Sundar Rajan

4

从理论上讲

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

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

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

在此处输入图片说明


3

基本上,作为Lix答案的扩展,访问代码路由允许资源所有者(即Facebook用户)注销其用户代理(即其浏览器)的授权,例如通过注销,而无需撤销对脱机客户端的授权(即,你的申请)。如果这并不重要,则无需使用访问代码路由。

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

这似乎类似于选择隐式授权代码授权流的问题。实际上,这是一个相反的观点?

另外,正如Drew所说

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

另一个是刷新令牌,但我认为在FB文档中解释得不够好。如果我是正确的,那么隐式授予(直接令牌)应该确实是短暂的,但这是必须执行的,而FB.js似乎隐藏了很多(我没有深入研究过的那个) 。

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


2

在带Facebook的OAuth 2.0中,总体概念很简单,如下所示。

步骤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请求发送来获取“访问令牌”

    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.使用从以上步骤获得的访问令牌并检索用户资源


1

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


-1

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


如果您是第一次请求权限,是否不能使用相同的令牌?并且,如果您具有offline_access,则可以保存令牌。我仍然对为什么流程中需要代码感到困惑...
jkeesh 2011年

您当然可以使用相同的令牌-但普通令牌会在一段时间后过期。TBH我从来没有使用的“代码”参数手动-我所有的登录完成后通过检索SDK的的loginURL ...
LIX

我认为目前仅在PHP SDK上。在最新的oauth2身份验证文档上,如果您想执行除PHP服务器端以外的任何操作,则需要使用“代码”
jkeesh 2011年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.