OAuth 2.0协议草案的第4.2节指出,授权服务器可以返回access_token(用于通过资源验证自己)和refresh_token,refresh_taken纯粹用于创建新的access_token:

https://www.rfc-editor.org/rfc/rfc6749#section-4.2

为什么两者都有?为什么不让access_token和refresh_token一样长,而不设置refresh_taken?


当前回答

Catchdave提供的讨论链接还有Dick Hardt提出的另一个有效的观点(原始的,死链接),我认为除了上面写的内容之外,这里还值得一提:

我记得刷新令牌是为了安全和撤销。<...>撤销:如果访问令牌是自包含的,则可以通过不发布新的访问令牌来撤销授权。资源不需要查询授权服务器以查看访问令牌是否有效。这简化了访问令牌验证,并使扩展和支持多个授权服务器更加容易。当访问令牌有效但授权被撤销时,有一个时间窗口。

事实上,在资源服务器和授权服务器是同一个实体的情况下,并且用户和其中任何一个之间的连接(通常)都是同样安全的,那么将刷新令牌与访问令牌分开并没有多大意义。

尽管如引用中所述,刷新令牌的另一个作用是确保用户可以随时(例如通过其配置文件中的web界面)撤销访问令牌,同时保持系统的可伸缩性。

通常,令牌可以是指向服务器数据库中特定记录的随机标识符,也可以包含自身的所有信息(当然,这些信息必须使用MAC进行签名)。

具有长期访问令牌的系统应该如何工作

服务器允许客户端通过发出令牌访问预定义范围内的用户数据。由于我们希望保持令牌的可撤销性,我们必须在数据库中存储令牌以及设置或取消设置的标志“已撤销”(否则,如何使用自包含令牌?)。数据库可以包含多达len(用户)x len(注册客户端)x len(范围组合)的记录。然后,每个API请求都必须命中数据库。虽然对执行O(1)的数据库进行查询非常简单,但单点故障本身可能会对系统的可伸缩性和性能产生负面影响。

具有长期刷新令牌和短期访问令牌的系统应该如何工作

在这里,我们发布两个密钥:带有数据库中相应记录的随机刷新令牌,以及签名的自包含访问令牌,其中包含过期时间戳字段。

由于访问令牌是自包含的,因此我们根本不必访问数据库来检查其有效性。我们所要做的就是解码令牌并验证签名和时间戳。

尽管如此,我们仍然需要保留刷新令牌的数据库,但对该数据库的请求数量通常由访问令牌的寿命定义(寿命越长,访问率越低)。

为了撤销特定用户对客户端的访问,我们应该将相应的刷新令牌标记为“已撤销”(或完全删除),并停止发布新的访问令牌。很明显,在一个窗口中,刷新令牌已被撤销,但其访问令牌可能仍然有效。

权衡取舍

刷新令牌部分消除了访问令牌数据库的SPoF(单点故障),但它们有一些明显的缺点。

“窗口”。事件“用户撤销访问”和“保证撤销访问”之间的时间间隔。客户端逻辑的复杂性。无刷新令牌使用访问令牌发送API请求如果访问令牌无效,则失败并要求用户重新验证带刷新令牌使用访问令牌发送API请求如果访问令牌无效,请尝试使用刷新令牌更新它如果刷新请求通过,则更新访问令牌并重新发送初始API请求如果刷新请求失败,请要求用户重新验证

我希望这个答案确实有意义,有助于某人做出更深思熟虑的决定。我还想指出,一些著名的OAuth2提供商,包括github和foursquare,采用了没有刷新令牌的协议,并对此感到满意。

其他回答

据我所知,如果您需要撤销访问,刷新令牌只是为了性能和成本节省。

例1:不实现刷新令牌;仅实现长期访问令牌:如果用户滥用服务(例如:不支付订阅),您需要能够撤销访问令牌=>您需要在每个需要访问令牌的API调用上检查访问令牌的有效性,这会很慢,因为它需要DB查找(缓存可以帮助,但这更复杂)。

例2:实现刷新令牌和短期访问令牌:如果用户滥用服务(例如:不支付订阅),您需要能够撤销访问令牌=>短暂的访问令牌将在短暂的白色(例如1小时)后过期,用户将需要获得新的访问令牌,因此我们不需要对需要访问令牌的每个API调用进行验证。您只需要在从刷新令牌生成访问令牌时验证用户。对于坏用户,如果无法生成访问令牌,则可以注销该用户。当用户尝试重新登录时,验证将再次运行并返回错误。

客户可以通过多种方式受到损害。例如,可以克隆手机。访问令牌过期意味着客户端被迫重新向授权服务器进行身份验证。在重新认证期间,授权服务器可以检查其他特征(IOW执行自适应访问管理)。

刷新令牌允许仅客户端进行重新身份验证,其中重新授权会强制与用户进行对话,许多用户表示他们不愿意这样做。

刷新令牌基本上适用于正常网站可能选择在一小时左右后定期重新验证用户的相同位置(例如银行网站)。由于大多数社交网站都不会重新验证网络用户,因此目前它的使用率并不高,那么他们为什么要重新验证客户端呢?

这些答案都没有找到刷新令牌存在的核心原因。显然,您总是可以通过将客户端凭据发送到身份验证服务器来获得新的访问令牌/刷新令牌对——这就是您首先获得它们的方式。

因此,刷新令牌的唯一目的是限制通过网络发送到身份验证服务的客户端凭据的使用。访问令牌的TTL越短,就越需要使用客户端凭据来获取新的访问令牌,因此攻击者就越有机会破坏客户端凭据(尽管如果使用非对称加密发送客户端凭据,这可能非常困难)。因此,如果您有一个一次性刷新令牌,您可以使访问令牌的TTL任意小,而不影响客户端凭据。

为了消除一些混淆,您必须了解客户机密码和用户密码的角色,这两个角色非常不同。

客户端是应用程序/网站/程序/。。。,该服务器希望通过使用第三方身份验证服务对用户进行身份验证。客户端机密是一个(随机)字符串,该字符串对此客户端和身份验证服务器都是已知的。使用这个秘密,客户端可以通过身份验证服务器识别自己,从而获得请求访问令牌的授权。

要获取初始访问令牌和刷新令牌,需要:

用户ID用户密码客户端ID客户机密

要获取刷新的访问令牌,客户端使用以下信息:

客户端ID客户机密刷新令牌

这清楚地表明了区别:在刷新时,客户端通过使用其客户端密钥来获得刷新访问令牌的授权,因此可以使用刷新令牌而不是用户ID+密码来重新验证用户。这有效地防止了用户必须重新输入他/她的密码。

这也表明,丢失刷新令牌是没有问题的,因为客户机ID和机密是未知的。它还表明,保持客户机ID和客户机机密是至关重要的。

让我们考虑一个系统,其中每个用户链接到一个或多个角色,每个角色链接到一种或多种访问权限。可以缓存这些信息以获得更好的API性能。但是,用户和角色配置可能会发生变化(例如,可能会授予新的访问权限,或者可能会撤销当前的访问权限),这些都应该反映在缓存中。

我们可以为此目的使用访问和刷新令牌。当使用访问令牌调用API时,资源服务器检查缓存的访问权限。如果有任何新的访问许可,则不会立即反映。一旦访问令牌过期(例如在30分钟内)并且客户端使用刷新令牌生成新的访问令牌,就可以使用来自DB的更新的用户访问权限信息来更新缓存。

换句话说,我们可以将昂贵的操作从使用访问令牌的每次API调用转移到使用刷新令牌生成访问令牌的事件。