OAuth 2.0协议草案的4.2节指出授权服务器可以返回a access_token(用于向资源验证自己)以及a refresh_token,它纯粹用于创建新的access_token:
https://tools.ietf.org/html/rfc6749#section-4.2
为什么两者都有?为什么不只是做到access_token最后只要refresh_token没有refresh_token?
我必须承认我已经有很长一段时间没有这个问题,从来没有真正理解过.
说auth令牌就像一个保险箱的钥匙,当它到期时它不再可用了.现在我们给了一个魔术刷新令牌,可用于获取另一个可用的键,另一个......直到魔术键到期.那么为什么不将auth令牌的到期时间设置为与刷新令牌相同?为什么这么麻烦?
它的正当理由是什么,也许是历史原因?真的很想知道.谢谢
我有一个与YouTube直播API集成的程序.它运行在计时器上,因此我可以通过刷新令牌每隔50分钟编程一次获取新的访问令牌.我的问题是,为什么?
当我通过YouTube验证时,它给了我一个刷新令牌.然后,我使用此刷新令牌大约每小时获取一个新的访问令牌.如果我有刷新令牌,我总是可以使用它来获得一个新的访问令牌,因为它永远不会过期.所以我不知道这是多么安全,而不仅仅是从一开始就给我一个访问令牌,而不是整个刷新令牌系统.
我已经读了一段时间了,没有任何意义,而且解释相互矛盾,评论证明了这一点。
到目前为止,我的理解是 JWT 存储由服务器编码的信息,可以有过期时间,并且服务器及其密钥可以解码其中的信息(如果它有效)。说得通。
它对于可扩展性很有用,因此独立的 API 可以解码并验证令牌中的信息,只要它们拥有密钥。此外,不需要将信息存储在任何数据库中,这与会话不同。说得通。
如果令牌被盗,API 无法判断令牌是否由正确的人使用。这是上面的缺点。
通过减少令牌的过期时间,可以减少安全漏洞,从而减少窃贼未经许可使用令牌的时间。(附带问题,但如果他们能够偷一次,他们可能也会偷第二次)
但是减少令牌的有效时间意味着每次令牌过期时用户都需要登录,并且如上所述,这种情况相当频繁,因此不会提供太好的用户体验。说得通。
从现在开始,一切都没有意义了:
引入刷新令牌可以解决这个问题,因为它的过期时间更长。使用刷新令牌可以生成访问令牌,因此只要用户拥有刷新令牌(时间较长)就可以登录,而被盗的访问令牌仍然仅在短时间内有效。
对我来说,上述内容似乎增加了一层额外的复杂性,而安全性没有任何改进。即对我来说,上面的内容似乎等于一个长期存在的访问令牌。
为什么?因为对我来说,刷新令牌基本上是一个访问令牌(因为这就是它生成的)。因此,拥有刷新令牌意味着无限制的访问令牌,因此无限制地访问 API。
然后我读到一个答案,刷新令牌和访问令牌是一对一的映射,因此窃取访问令牌仍然意味着对 API 的未经授权的访问,但只持续很短的时间,并且窃取刷新令牌将生成不同的访问令牌,以便 API 可以检测到异常(同一帐户使用不同的访问令牌),从而使访问令牌失效。
看来我不是唯一一个对这个问题感到困惑的人。
如果上述情况不正确,刷新令牌有何真正帮助?
如果上述情况成立,并且确实存在刷新令牌和访问令牌的一对一映射:
如果有人能澄清这个问题那就太好了,因为从 5 个解释中,有 5 个相互冲突的陈述(有时相同的解释包含冲突的信息),并且许多开发人员都想了解这种方法。
我有一个 Api 和一个移动客户端。我使用刷新令牌如下:
问题:假设用户有 2 个设备,A 和 B。他使用设备 A 成功登录,因此他获得了 2 个令牌,他很高兴。一旦用户从设备 B 登录,Api 就会向他发送一对新的令牌,这意味着新的刷新令牌将覆盖设备 A 已经给定的令牌。现在用户返回设备 A aaa,它就消失了(无效刷新)令牌!)所以他必须再次提供凭据,而我、用户和您都不希望这样做。
建议:我找到了两种解决问题的方法,但因为我对这个主题还很陌生,所以我看不出哪种方法是最佳实践:
方法 A:为每个用户保存多个刷新令牌,并保存设备标识符(仍然不知道在移动、浏览器和桌面客户端等不同客户端类型的情况下究竟会发生什么!)但无论如何。在此方法中,当用户从设备 A 登录时,Api 会提供两个令牌。用户从设备 B 登录,Api 会传递新的令牌对。他返回设备 A,再次使用他的第一个令牌(仍然有效)。
方法 B:为每个用户保留 1 个刷新令牌。当用户从设备 B 登录时,Api 发回唯一的刷新令牌(只要用户提供有效的凭据,我就不应该关心设备,对吧?)
您能指出每种方法的优缺点吗?
在我的应用程序中,当用户成功登录时,我返回访问令牌和刷新令牌.访问和刷新令牌的到期时间分别设置为10和40分钟.(我应该对这些值做更多的研究.这只是为了测试)
我使用了下面文章中描述的实现
http://www.svlada.com/jwt-token-authentication-with-spring-boot/
假设我在登录10分钟后向服务器发出请求.由于访问令牌已过期,我收到401错误响应.
但是,作为初学者,我发现很难理解是否需要显式发送刷新令牌以获取新的访问令牌.如果我应该这样做,怎么做?我应该发送刷新令牌作为什么?标题?
或者,当我的请求被服务器拒绝,因为访问令牌已过期,刷新令牌本身是否会自动向服务器发送请求以获取新的访问令牌?
我发现很难从网上找到的资源中理解刷新令牌行为的本质.请在这些问题上澄清我.
由于这个答案,我可以通过HTTP REST API和电子邮件/密码连接到Firebase 3.使用此API登录会返回用于访问Firebase数据库的访问令牌.此访问令牌在1小时后到期.登录后还会返回刷新令牌,我可以使用它来刷新访问令牌.这是我具体做的事情:
方法:
POST
Run Code Online (Sandbox Code Playgroud)
网址:
https://www.googleapis.com/identitytoolkit/v3/relyingparty/verifyPassword?key=<my-firebase-api-key>
Run Code Online (Sandbox Code Playgroud)
有效载荷:
{
email: "<email>",
password: "<password>",
returnSecureToken: true
}
Run Code Online (Sandbox Code Playgroud)
响应:
{
"kind": "identitytoolkit#VerifyPasswordResponse",
"localId": "<firebase-user-id>", // Use this to uniquely identify users
"email": "<email>",
"displayName": "",
"idToken": "<provider-id-token>", // Use this as the auth token in database requests
"registered": true,
"refreshToken": "<refresh-token>",
"expiresIn": "3600"
}
Run Code Online (Sandbox Code Playgroud)
在刷新我的访问令牌的情况下:
网址:
https://securetoken.googleapis.com/v1/token?key=<my-firebase-api-key>
Run Code Online (Sandbox Code Playgroud)
有效载荷:
{
grant_type: "refresh_token",
refresh_token: "<refresh-token>"
}
Run Code Online (Sandbox Code Playgroud)
响应:
{
"access_token": "<access-token>",
"expires_in": "3600",
"token_type": "Bearer",
"refresh_token": "<refresh-token>",
"id_token": "<id-token>",
"user_id": "<user-id>",
"project_id": …Run Code Online (Sandbox Code Playgroud) access-token firebase firebase-authentication firebase-realtime-database refresh-token
我有一个谷歌批准的谷歌 OAuth2 客户端,它提供对用户帐户所需范围的离线访问。我的后端应用程序存储并使用刷新令牌在需要时刷新访问令牌。
最近,我们看到我们的令牌刷新尝试遇到了来自谷歌的错误:
{
"error" : "invalid_grant",
"error_description" : "Token has been expired or revoked."
}
Run Code Online (Sandbox Code Playgroud)
没有其他信息。
我的 Google OAuth 客户端没有任何变化。用户未更改帐户密码。用户尚未撤销对我客户的访问权限。
令牌刷新时突然出现此类错误的原因可能是什么?我将来如何避免这种情况(如果可能)?
我正在使用 Laravel 6.7 并尝试使用Passport进行用户身份验证。
我可以在用户注册时为他们创建访问令牌。这是代码:
$user = User::create($input);
$user->createToken('auth-token');
Run Code Online (Sandbox Code Playgroud)
正如我在AuthServiceProvider.php文件boot()函数中定义的那样,此访问令牌的有效期为 15 分钟,如下所示:
Passport::personalAccessTokensExpireIn(Carbon::now()->addMinutes(15));
Run Code Online (Sandbox Code Playgroud)
我想使用刷新令牌刷新它,但似乎无法理解如何。
我到处找(包括 Laravel 网站),他们都告诉我这样做:
$http = new GuzzleHttp\Client;
$response = $http->post('http://your-app.com/oauth/token', [
'form_params' => [
'grant_type' => 'refresh_token',
'refresh_token' => 'the-refresh-token',
'client_id' => 'client-id',
'client_secret' => 'client-secret',
'scope' => '',
],
]);
Run Code Online (Sandbox Code Playgroud)
没有任何明确的解释,以什么价值观'the-refresh-token','client-id'并'client-secret'意味着是。
堆栈溢出的一个答案如下:
您必须发送旧的刷新令牌 (
'refresh_token' => 'the-refresh-token') 并且此代码生成一个新令牌和刷新刷新。
但是我没有刷新令牌,我正在尝试创建一个。我只是创建一个随机字符串吗?
我正在设计一个新的 Web 应用程序,需要 oAuth2 实现。我一直在阅读 PKCE 的 oAuth2 授权代码流程。这是有道理的,它确保启动授权代码流的客户端与交换访问令牌(和/或刷新令牌)的授权代码的客户端是同一客户端。
但后来我想知道我们如何处理刷新令牌。据我所知,BFF 现在是首选解决方案,我们使用一个单独的组件(前端的后端)来处理来自 Web 应用程序的所有调用并将这些调用代理到后端 api,同时处理所有访问令牌和刷新令牌。Web 应用程序和 BFF 维护一个会话 cookie,因此 BFF 可以跟踪应将哪个访问令牌添加到哪个请求等。
大多数博客都提到“如果您将会话 cookie 设置为严格且仅 http 且安全,这是安全的,因为这样恶意 JS 就无法获取该 cookie”。
这就是我难以理解为什么这更安全的地方。如果 cookie 足够安全来处理会话 ID,那么为什么它们不够安全来处理访问令牌呢?或者甚至刷新令牌?如果它们是基于 cookie 的,那么它们会随每个请求一起发送,并且恶意 JS 无法访问它。如果可以,那么 BFF 模型不会提供任何额外的安全性,只是稍微复杂一点,不是吗?
所以底线是:如果 BFF 被认为是安全的(r),因为会话保存在安全的仅 http cookie 中,为什么将访问/刷新令牌保存在安全的仅 http cookie 中不安全?
cookies access-token oauth-2.0 single-page-application refresh-token
refresh-token ×10
access-token ×8
oauth ×3
jwt ×2
oauth-2.0 ×2
security ×2
cookies ×1
firebase ×1
google-api ×1
google-oauth ×1
laravel ×1
spring-boot ×1
youtube-api ×1