英文:
How and why handle jwt token expiration with refresh_token, is there another alternative?
问题
我有两个战争文件:app.war
(struts web 应用程序)和 rest.war
(经典 REST API)。
app.war
通过 JWT 令牌访问 rest.war
,该令牌是用户成功登录 app.war
后生成的。
当用户使用 app.war
时,需要从 rest.war
获取一些数据,方法是从 app.war
的 JSP 发送带有 JWT 令牌的 Ajax 调用。
JWT 令牌的过期时间为 15 分钟,而 app.war
的会话超时为 1 小时。
然而,如果 JWT 令牌过期,将会弹出一个提示要求用户重新登录,尽管用户仍然可以访问 app.war
。
有一种替代方法:使用 access_token
和 refresh_token
,如果 access_token
过期,然后使用 refresh_token
获取新的 access_token
和 refresh_token
。
对于这种方法,我有一些问题:
第一,为什么要使用两个令牌?因为我认为它们是相同的,只是 refresh_token
的生存时间比 access_token
长,使用 refresh_token
获取新的 access_token
,那么为什么不只使用 access_token
并设置其过期时间更长呢?
第二,生成 access_token
和 refresh_token
是否使用相同的算法,只是它们的过期时间不同?
第三,如果客户端执行多个使用令牌的 API 调用(同步和异步),如果其中一个调用返回 401(令牌过期),应该如何处理?
英文:
I have two wars: app.war
(struts web app) and rest.war
(classic rest api).
app.war
access rest.war
by jwt token which is generated once user login app.war
successful.
When user use a.war
, some data need to be got from rest.war
by sending ajax calls from jsp of a.war
with jwt token.
The expired time of jwt token is 15 mins, while session timeout of app.war
is 1 hour.
However, if jwt token is expired, there is pop up ask for user login again even and user still can access app.war
.
There is one alternative: use access_token
and refresh_token
, if access_token
expired, then use refresh_token
to get new access_token
and refresh_token
.
For this approach, I have some questions:
First, Why use two tokens? because i think they are the same, just refresh_token
live longer than access_token
and use refresh_token
to get new access_token
, so why not just access_token
and set its expired time longer?
Second, is it same algorithms to generate access_token
and refresh_token
, just their expired is different?
Third, if client perform several api invocations (sync & async) using the token, how handle if one of that invocations return the 401 (token expired) ?
答案1
得分: 5
正如你所说,refresh_token是处理JWT过期的推荐替代方案。
为什么要使用两个令牌?
因为使用两个令牌(access_token和refresh_token)是世界一流公司(Google、Azure、Amazon等)采用的经过验证的策略,它们信任OAuth 2.0授权框架。
这是互联网工程任务组(IETF)的产品,而IETF又是:互联网工程任务组(IETF)是一个开放的标准组织,它开发并推广自愿的互联网标准,特别是组成互联网协议套件的标准。
你可以严格遵守其规范,创建并专注于满足你的自定义需求,或者开发一个具有新概念的新框架。
那么为什么不只使用access_token并将其过期时间设置得更长呢?
OAuth2规范不建议使用永不过期的令牌。令牌本身就意味着有过期性。如果它不过期,我们可以使用密码。
例如,想象一个需要令牌来下载某些用户信息的移动应用程序。如果令牌不过期,小偷可能会偷走移动应用程序,进入并访问用户信息。但由于令牌意味着有过期时间,小偷只能有限时间内访问。此外,令牌可以在被盗窃时被用户吊销,因此小偷无法继续访问。
通常情况下,令牌过期后,需要重新登录。但在某些情况下,用户可能不希望每3600毫秒重新登录。因此,refresh_token有助于不干扰我们的用户,无需人工登录即可获取新的access_token。那么,如果refresh_token不过期会发生什么?我们可以创建几个月或几年的访问令牌吗?这就是refresh_token也必须过期的原因。
生成access_token和refresh_token的算法是相同的吗,只是它们的过期时间不同吗?
我实现了一种安全服务器,我使用了相同的算法,只是过期时间不同。但我添加了一个额外的声明来区分它们:
多次调用需要access_token
在这种情况下,如果令牌在每次用户登录时都被更新,你将拥有一个准备好用于3600毫秒的access_token。
之后,你的用户就像一个机器人(或者是你的网站的一个功能/需求),开始使用多个表单来执行对你的REST API的多次调用,附加了access_token。
如果我们处于3601毫秒时,在下一次来自网站的API调用中,API必须返回403错误,并显示一个经典的弹出窗口:会话已过期,单击此处重新登录...
如果你的需求是避免这个弹出窗口,你可以选择以下其中一种方法:
- 在403错误时使用刷新令牌来更新令牌。在这种情况下,你可以使用axios-retry来处理错误重试。
- 登录后,启动一个异步任务以在比令牌到期时间更短的时间间隔内更新令牌。在我们的示例中为3400毫秒。因此,来自你的网站的API调用永远不会失败。
建议
在后端层执行access_token和refresh_token的交换,而不是在前端(Ajax)层执行。
这样,攻击者将永远不会知道获取令牌或刷新令牌的端点。
英文:
As you said, refresh_token is the recommended alternative to deal with jwt expiration.
why use two tokens?
Because the use of two tokens (access_token and refresh_token) is a verified strategy used by world class companies (google, azure, amazon, etc) which trust in The OAuth 2.0 Authorization Framework
Which is a product of the Internet Engineering Task Force (IETF) which in turn is : The Internet Engineering Task Force (IETF) is an open standards organization, which develops and promotes voluntary Internet standards, in particular the standards that comprise the Internet protocol suite.
You can use the oauth2 framework rigidly complying its specification, create and hybrid focus on your custom requirements or develop a new framework with new concepts
so why not just access_token and set its expired time longer?
Oauth2 spec does not recommend a non-expirable token. Token word itself mean a expirable thing. If it doesn't expire, we could use a password.
For example let's imagine a mobile app which needs a token to download some user information. If token does not expire, a thief could steal the mobile app, enter and access to the user info. But as token means expiration, the thief could have a time limited access. Also token could be revoked by the user at the steal time, so the thief could not has access.
Commonly when token expire, a login is forced. But there some requirements in which user doesn't want to login and login again every 3600 ms. So refresh_token helps to don't disturb to our user and get a new access_token without human login. Now, what happen if refresh_token didn't expire? Can we create access-tokens from months or years? That is why refresh_token must expire too
is it same algorithms to generate access_token and refresh_token, just their expired is different?
I implemented a kind of security server and I used the same algorithm with different expiration. But I added a extra claim to to differentiate them:
Several invocations needs the access_token
In this case, if token is renewed at every user login, you will have an access_token ready to use with 3600ms of life.
After that your user is kind of robot ( or is a feature/requirement of your web ) and start to use multiple forms which perform several invocations to your rest api attaching the access_token.
If we are in the 3601ms, in the next api invocation from web, the api must return a 403 error and show a classic popup: Session expired, click here to login again...
If your requirement is avoid this popup, you could choice one of these approaches:
- Renew token using the refresh token on 403 error. In this case you could use axios-retry to deal with retry on error.
- After login, start an async task to renew the token at intervals less than token expiration. 3400ms in our example. So api invocations from your web never fail
Advice
Perform access_token and refresh_token exchange in your backend layer, not in frontend (ajax) layer.
So the attackers will never know your endpoint to get tokens or refresh them.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论