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?


当前回答

这一切都与扩展和保持资源服务器无状态有关。

您的服务器/资源服务器服务器是无状态的,这意味着不检查任何存储以快速响应。通过使用公钥验证令牌的签名来执行此操作。检查每个请求的access_token。通过只检查access_token的签名和过期日期,响应速度非常快,并允许扩展。access_token应该有很短的到期时间(几分钟),因为如果它被泄露,就没有办法撤销它。身份验证服务器/OAuth服务器服务器不是无状态的,但它可以,因为请求要少得多。仅在access_token过期时检查refresh_token。(例如每2分钟)请求速率远低于资源服务器。将刷新令牌存储在数据库中,并可以撤消它。refresh_token可能有很长的到期时间(几周/几个月),如果它被泄露,有办法撤销它。

不过有一个重要的注意事项,身份验证服务器的请求要少得多,因此可以处理负载,但是由于必须存储所有refresh_token,因此可能存在存储问题,如果用户急剧增加,这可能会成为一个问题。

其他回答

我在这里获得了一些额外的资源,这些资源澄清了我们为什么需要refresh_token的某些问题。这些资源的一些要点如下:

在现实世界中,最好使用名为authServer和resourceServer/s的独立服务器authServer-仅用于身份验证和授权。该服务器的职责是发布刷新令牌、访问令牌以及登录和注销用户resourceServer-此服务器(也可以是负载平衡的多个服务器)提供受保护的数据。例如,这些数据可以像电子商务项目中的产品、评论等refresh_token的一个用途是,每次需要新的access_token时,我们不必通过网络(从前端到authServer)发送用户名和密码(凭据)。这应该只在第一次完成(当您还没有refresh_token时),refresh_taken将立即从authServer获取新的access_token,这样您就可以继续向受保护的resourceServer发出请求。这里的优点是,用户不必每次都提供凭据,因此用户的用户名和密码不容易被泄露。refresh_token的另一个主要用途是,假设您的authServer与现实世界中的resourceServer(第三方服务,如auth0、okta、azure等,或您自己的实现)相比非常受保护。您只需将access_token发送到resourceServer(以获取数据),而无需向resourceServer发送refresh_token。因此,当您的access_token发送到resourceServer时,很有可能会有黑客拦截您的resourceServer(因为它不像authServer那样安全),从而访问您的短暂访问权。因此,access_token的寿命很短(例如30分钟)。记住,当这个access_token过期时,您将向authServer(它比resourceServer更安全)发送refresh_token以获取新的access_toke。由于您在任何时候都不会向resourceServer发送refresh_token,因此拦截resourceServer的黑客不可能获得您的refresh_taken。如果作为一名开发人员,您仍然怀疑用户的refresh_token也可能被黑客入侵,那么您可以注销所有用户(使refresh_taken对所有用户无效),这样用户将再次登录(提供用户名和密码)以获得新的refresh_token+access_token,事情将再次步入正轨。

一些有用的资源

具有或不具有刷新令牌的工作流-Youtube

JWT认证代码示例-节点JS-Youtube

刷新令牌的思想是,如果访问令牌因其短暂而受到破坏,攻击者可以在有限的窗口中滥用它。

刷新令牌(如果被破坏)是无用的,因为攻击者除了需要刷新令牌之外还需要客户端id和密码,以便获得访问令牌。

话虽如此,由于每次对授权服务器和资源服务器的调用都是通过SSL完成的,包括请求访问/刷新令牌时的原始客户端id和secret,因此我不确定访问令牌如何比长期刷新令牌和客户端id/secret组合更“不可妥协”。

当然,这与不同时控制授权服务器和资源服务器的实现不同。

这里有一个很好的线程,讨论了刷新令牌的使用:OAuth存档。

引用上述内容,讨论刷新令牌的安全目的:

刷新令牌。。。降低长期access_token泄漏的风险(在不安全的资源服务器上的日志文件中查询参数,测试版或编码不良的资源服务器应用程序,非https站点上的JS SDK客户端将access_toke放入cookie等)

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

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

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

这个答案来自Justin Richer通过OAuth 2标准正文电子邮件列表。这是在他的许可下发布的。


刷新令牌的生命周期取决于(AS)授权服务器-它们可以过期、被撤销等。刷新令牌和访问令牌的区别在于受众:刷新令牌只返回授权服务器,访问令牌返回(RS)资源服务器。

此外,仅仅获得访问令牌并不意味着用户已经登录。事实上,用户可能已经不在那里了,这实际上是刷新令牌的预期用例。刷新访问令牌将允许您代表用户访问API,但不会告诉您用户是否在那里。

OpenIDConnect不仅从访问令牌提供用户信息,还提供ID令牌。这是一个单独的数据块,指向客户端本身,而不是AS或RS。在OIDC中,如果您可以获得一个新的ID令牌,您应该只考虑某人实际通过协议“登录”。刷新它可能还不够。

有关更多信息,请阅读http://oauth.net/articles/authentication/

刷新令牌和访问令牌只是术语。

这个小小的类比可以帮助巩固使用访问令牌和刷新令牌背后的理论基础:

假设Alice通过邮寄给Bob一张支票,该支票可以在出票后1小时内兑现(假设),否则银行不会兑现。但Alice还在给银行的邮件中附上了一张纸条,要求银行接受并兑现支票,以防支票延迟(在规定范围内)

当Bob收到这张支票时,如果他看到这张支票被篡改(令牌篡改),他将自己丢弃这张支票。如果没有,他可以把它拿到银行兑现。在这里,当银行注意到发行时间超过了1小时的时限,但看到Alice的签名通知,要求银行在规定的延迟范围内兑现。

看到这张纸条后,银行会尝试验证签名的消息,并检查Alice是否仍然具有正确的权限。如果是,银行将支票兑现。鲍勃现在可以向爱丽丝承认这一点了。

虽然不是非常准确,但这个类比可以帮助您注意到处理事务所涉及的不同部分:

Alice(发件人-客户)Bob(接收者-资源服务器)银行(授权服务器)验证过程(数据库访问)支票(访问令牌)备注(刷新令牌)

主要是,为了优化可伸缩性,我们希望减少对Auth Server以及最终对数据库的API调用次数。我们需要在方便和安全之间取得适当的平衡。

注意:与链中的资源服务器相比,让Auth服务器更早地响应请求当然更常见。