ChatGPT解决这个技术问题 Extra ChatGPT

OpenID Connect 中 ID 令牌到期时间的意图是什么?

在 OpenID Connect 中,访问令牌具有到期时间。对于授权代码流,这通常很短(例如 20 分钟),之后您使用刷新令牌请求新的访问令牌。

ID 令牌也有到期时间。我的问题是这样做的目的是什么?

任何小于刷新令牌到期时间的 ID 令牌到期时间都意味着您最终将拥有一个过期的 ID 令牌,但它是一个有效的访问令牌。

你的意思是:

将您的 ID 令牌的有效期设置为比刷新令牌的有效期长,或者

将其设置为与访问令牌相同的到期时间,并在到期时采取一些措施(什么?),或者

只是在收到时在您的客户端中使用 ID 令牌,然后忽略之后的到期时间?

OpenID Connect specification 只是说在验证 ID 令牌时,

"The current time MUST be before the time represented by the exp Claim."

其中(可能)支持上面的第三个选项。

编辑

由于 OpenID Connect 建立在 OAuth2 之上,因此可以在 OAuth2 specification 中找到对以下补充问题的答案,其中说:

expires_in
     RECOMMENDED.  The lifetime in seconds of the access token.

一个相关的问题是,当您为令牌交换授权代码时,相同的规范说您可能会收到如下响应:

{
 "access_token": "SlAV32hkKG",
 "token_type": "Bearer",
 "refresh_token": "8xLOxBtZp8",
 "expires_in": 3600,
 "id_token": "eyJhbG[...]"
}

但是在这种情况下,“expires_in”与什么有关?访问令牌、刷新令牌还是 ID 令牌?

(有关信息,IdentityServer3 将其设置为访问令牌到期时间)。


A
Appetere

我正在回答我自己的问题,因为我发现我的问题背后的一些假设是错误的,所以在这里更容易澄清,而不是重新编写问题。

ID 令牌用于向客户证明用户已通过身份验证,以及他们的身份。

当客户端收到一个 ID 令牌时,它通常会做一些事情,比如将其转换为 ClaimsIdentity,并保持它,例如使用 cookie。

ID 令牌在使用时必须未过期(应该是,因为它刚刚被发布)。但是在此之后它不会再次使用,因此它是否过期而用户仍然具有活动会话并不重要。客户端拥有所需的身份验证信息,进而可以选择自己的策略来确定会话在用户必须再次登录之前的持续时间。

当我问这个问题时,我的错误假设是 ID 令牌和访问令牌应该一起使用,因此两者都需要有有效的到期日期。这是错误的,原因有很多:

ID 令牌仅用于向客户端进行身份验证(如上所述)。

访问令牌与客户端无关。它们用于访问资源,客户端仅在需要调用资源时才处理它们。

像独立的 MVC 或 WebForms 应用程序只需要一个 ID 令牌。如果它没有调用外部资源,则没有可以授予访问权限的内容,因此没有访问令牌。


你有这方面的参考吗? Eugenio 声称您可以在他的回答中刷新 id 令牌。这是真的?
您无法刷新 ID 令牌,就延长其到期时间而言(就像使用脱机访问令牌可以刷新访问令牌一样)。但是,如果您与 OpenID Connect Provider 有一个未过期的身份验证会话(例如登录 IdentityServer3 后的 cookie),那么当您重复登录请求时,Provider 可以跳过身份验证(因为 cookie 表明您已经完成了)并返回一个新的 ID 令牌(如果需要,还有访问令牌)。当然,这仅适用于 cookie 的生命周期比 ID 令牌更长的情况。
虽然您可以这样做,但我不确定这样做是否正确。它对最终用户来说也不是无缝的,因为它需要一些浏览器重定向。
@Kir如果您使用的是Javascript单页应用程序(SPA),那么访问令牌更新的第一次尝试通常是后台进程,因此最终用户不会被打断。例如,如果您的资源的 API 响应访问令牌已过期,则 SPA 会向身份服务器发出后台请求以获取新的访问令牌。仅当此操作失败(因为 ID 令牌已过期)时,您才必须要求用户再次登录。有关示例代码,请参阅 github.com/IdentityServer/IdentityServer3.Samples/tree/master/… 处的 JavascriptImplicitClient 示例。
@Nth.gol 当您从 IdP 请求访问令牌时,您指定“范围”参数。这可以包括 IdP 可能在用户信息端点上支持的“配置文件”和“电子邮件”等范围,所以是的,它可以保护 IdP 资源,如您所说。但是您也可以为您的资源(例如 API)指定范围,“api1, api2”,因此相同的访问令牌也用于保护这些资源。
V
VadymVL

由于自己的原因,我不得不深入研究并写下来,所以我将在这里发布我学到的东西......

首先,我将冒着陈述显而易见的风险来回答问题:如果当前时间大于过期时间,则 ID 令牌不可信,并且必须忽略其内容。提问者的回答指出,在用户初始认证后,ID Token 不再使用。但是,由于 ID 令牌是由身份提供者签名的,因此在任何时候提供一种可靠地确定用户对于应用程序可能正在使用的其他服务的身份的方法肯定会很有用。使用简单的用户 ID 或电子邮件地址并不可靠,因为它很容易被欺骗(任何人都可以发送电子邮件地址或用户 ID),但由于 OIDC ID 令牌是由授权服务器签名的(这通常也具有作为第三方)它不能被欺骗,并且是一种更可靠的身份验证机制。

例如,移动应用程序可能希望能够告诉后端服务正在使用该应用程序的用户是谁,并且它可能需要在初始身份验证后的短暂时间之后这样做,此时 ID 令牌已过期,因此,不能用于可靠地对用户进行身份验证。

因此,就像访问令牌(用于授权 - 指定用户拥有哪些权限)可以刷新一样,是否可以刷新 ID Token(用于身份验证 - 指定用户是谁)?根据 OIDC 规范,答案并不明显。在 OIDC/OAuth 中,有三个“流程”用于获取令牌,授权代码流程、隐式流程和混合流程(我将在下面跳过,因为它是其他两个的变体)。

对于 implicit flow in OIDC/OAuth,您通过将浏览器中的用户重定向到授权端点并包括 id_token 作为 response_type 请求参数的值来在授权端点请求 ID 令牌。 Implicit Flow Successful Authentication Response 需要包含 id_token

对于 the Authentication Code flow,客户端在将用户重定向到授权端点时将 code 指定为 response_type 请求参数的值。成功的响应包括一个授权码。客户端客户端使用授权代码向令牌端点发出请求,并且根据OIDC Core Section 3.1.3.3 Successful Token Response 响应必须包含 ID 令牌

因此,对于任一流程,这就是您最初获取 ID 令牌的方式,但您如何刷新它呢? OIDC Section 12: Using Refresh Tokens 有以下关于刷新令牌响应的声明:

成功验证刷新令牌后,响应正文是第 3.1.3.3 节的令牌响应,但它可能不包含 id_token。

可能不包含 ID 令牌,并且由于没有指定强制它包含 ID 令牌的方法,因此您必须假设响应将不包含 ID 令牌。因此,从技术上讲,没有指定的方法可以使用刷新令牌“刷新”ID 令牌。因此,获取新 ID Token 的唯一方法是通过将用户重定向到授权端点来重新授权/验证用户并启动上述隐式流程或身份验证代码流。 OIDC 规范确实向 authorization request 添加了一个 prompt 请求参数,因此客户端可以请求授权服务器不使用任何 UI 提示用户,但重定向仍然必须发生。


如果您正在编写通用软件以与任意授权提供程序一起使用,则不能依赖从刷新返回 id_token。但是,如果您正在使用特定的提供者(例如 IdentityServer4),您可以检查它的功能,并使用刷新请求后收到的 id_token
那么如何刷新 id_token 呢?
@jwilleke AFAIK,如上所述“获取新 ID 令牌的唯一方法是通过将用户重定向到授权端点来重新授权/验证用户”
@MichaelFreidgeim 有趣,您是指通过 Open ID Connect Discovery mechanism 吗?我们究竟是如何做到的?
关于“刷新的响应体可能不包含 id_token”的好答案。赞成。顺便说一句,我的理解是 OIDC 规范确实为使用 Refresh Token 获取新的 ID 令牌留下了余地:客户端可以通过将“id_token”指定为范围之一来做到这一点;但是这里仍然需要注意一般性的警告,因为最终决定是否遵守您请求的范围是由身份验证服务器做出的。
M
Morrowless

如果我理解正确,根据 thisOpenID Connect Core 1.0 spec,ID 令牌本身可以存储在 cookie 中作为持久会话的机制,并与每个需要身份验证的请求一起发送给客户端。然后,客户端可以在本地或通过提供者的验证者端点(如果提供,like Google does)验证 ID 令牌。如果令牌过期,它应该发出另一个身份验证请求,除了这次在 URL 参数中使用 prompt=none。还要确保在 id_token_hint 参数中发送过期的 ID 令牌,否则 Provider 可能会返回错误。

因此,ID 令牌过期似乎很自然,但 prompt=none 确保可以在没有用户干预的情况下顺利获得新的 ID 令牌(当然,除非用户从该 OpenID 注销)。


E
Eugenio Pace

意图相同:id_token 过期后无法使用。主要区别在于 id_token 是一种数据结构,您无需调用任何服务器或端点,因为信息已编码在令牌本身中。常规 access_token 通常是不透明的工件(如 GUID)。

id_token 的使用者必须始终验证它的(时间)有效性。

我对 IS 不是 100% 熟悉,但我猜这是一个便利领域。您应始终检查 exp 声明。

过期只是验证之一。 id_tokens 也经过数字签名,这也是您必须执行的验证。


谢谢尤金尼奥。我的主要问题是当 ID 令牌过期时你应该怎么做?我认为(可能是错误的)要更新一个短暂的访问令牌,您必须使用刷新令牌。但是,如果 ID-token 与 access-token 的有效期相同,您将立即拥有一个过期的 ID-token,因此刷新 access-token 似乎毫无意义。想我可能在这里遗漏了一些东西!
您将使用(未撤销的)refresh_token 来获取新的 access_token 或 id_token。或者干脆以用户身份再次登录。 id_tokens 在逻辑上等同于 access_tokens。只是格式不同。
我的最新理解是,当用户与授权服务器进行经过身份验证的会话时,当访问令牌过期时,401 => 302 重定向到授权服务器将获得新的访问和 ID 令牌,而无需用户干预。但在离线模式下,refresh_token 只会返回一个新的 access_token,表示允许特定用户访问某些资源。它不能返回 id_token,因为这表示特定用户已通过身份验证,并且在离线模式下并非如此。
对于关于 id_token 和 access_token 之间有什么区别的问题(尤其是在使用不透明/参考令牌时),这将是一个很好的答案。重点先回答问题,再理清access token和id token是怎么用的?
p
pashute

刷新令牌意味着即使用户未登录,您也可以再次使用它从授权服务器(在本例中为 OP - OpenID-Connect 提供程序)请求某些内容。您通常只允许有限的资源使用此操作,并且仅在用户登录并至少经过一次身份验证后才允许这样做。刷新令牌本身也应该有时间限制。

在 OIDC 隐式流程中,您调用授权端点,并在响应中接收 ID 令牌以及所有范围以及其中的所有声明信息。对 API 的后续调用是通过代码流来完成的。隐式流旨在启用仅 javascript 或仅浏览器应用程序。不是与服务器交互的应用程序。因此,即使有一种方法可以“刷新”这个令牌,你也不应该 - 出于安全考虑 - 让它的存在时间过长。它将被冒充该 id 的未经授权的用户窃取和重复使用。您应该为此强制重新登录。

在代码流中,您调用 OP 的授权端点,并接收授权码(也称为授权令牌,或简称 authcode)。这应该与您在隐式流中收到的 id_token 类似,出于相同的原因,并且不能也不应该更新。

然后,您的 UI 或应用程序调用 OP 的 Token 端点,并接收(有时在用户通过 UI 进一步同意以允许在 OP 的服务器上使用他们拥有的资源之后):

用于身份验证的 id_token - 永远不应在服务器调用中再次使用它,除非在注销期间作为提示,当它的过期不再重要时,因此,由于上述原因,应该让其过期,并且永远不要刷新。

一个 access_token - 稍后在调用 API 时,可以将其提供给 OP 的 UserInfo 端点。这将返回声明,API 可以相应地进行授权。

您可以刷新此 access_token,因为它只告诉 API 用户拥有哪些声明,以及用户同意向您提供哪些资源(按范围和每个范围的声明)。如上所述,这是为了即使在用户不再登录后也允许访问。当然,您绝不希望允许刷新 id_token,因为您不想在不登录的情况下允许模拟。


你所说的关于隐式流程的部分是不正确的。使用隐式流的客户端可以获取除了 ID 令牌之外的访问令牌,并且可以使用该访问令牌与服务器交互。
有一种常见的做法是,当 id_token 过期时,客户端向服务器请求新的令牌,这样用户就不需要再次授权。例如参见damienbod.com/2017/06/02/…
d
dgonee

我想将此答案作为评论发布,但由于我在 StackOverflow 上不是很活跃,我想我将其作为替代答案发布。

在尝试将用户从会话 http://openid.net/specs/openid-connect-session-1_0.html 中注销时,您还可以使用 id_token 作为 id_token_hint。老实说,我认为此时 id_token 是否过期并不重要,因为您只关心注销特定用户。


S
Shaun Luttin

TLDR;

在相信它所说的之前验证 ID 令牌。

更多细节

OpenID Connect 中 ID 令牌到期时间的意图是什么?

目的是允许客户端验证 ID 令牌,并且客户端必须在使用 ID 令牌信息的操作之前验证 ID 令牌。

the OpenID Implicit Flow spec

如果本文档中定义的任何验证过程失败,则必须中止任何需要未能正确验证的信息的操作,并且不得使用无法验证的信息。

为了证实这一点,Google's OpenID Connect documentation 谈到了 ID 令牌验证:

使 ID 令牌有用的一件事是,您可以在应用程序的不同组件中传递它们。这些组件可以使用 ID 令牌作为对应用程序和用户进行身份验证的轻量级身份验证机制。但在您可以使用 ID 令牌中的信息或将其作为用户已通过身份验证的断言之前,您必须对其进行验证。

因此,如果我们的客户端应用程序要根据 ID 令牌的内容采取一些行动,那么我们必须再次验证 ID 令牌。


J
Jeb50

简单分享一下我的旅程。现在是 2021 年 6 月。我写这篇文章是因为我偶然发现了 3rd-party 身份验证业务。我是一名资深程序员,但对安全性很陌生。换句话说,所有的标准、规范和术语都是陌生的,任何人都可以在这个领域击败我。请原谅我没有遵守所有条款。

切入正题,我正在编写一个 Angular/Node 应用程序,所以 UI=Angular,API(API 服务器)=Node/Express。我没有创建自己的用户名/密码身份验证,而是转向第三方身份验证,让他们验证用户声称的真实性。这里有两本对我来说很重要的指南:

Angular Authentication With JSON Web Tokens (JWT): The Complete Guide Eiji's Authenticate with a backend server

结合 No. 1 和 angularx-social-login,我将 UI 与 Google 连接起来,然后将 idToken 附加到 API,vola!以下 2 号使用本地库 API 可以验证 idToken,太棒了!

等等,idTokenexp 在 1 小时后过期。我该如何刷新它?

我的理解是我所需要的只是谷歌的身份验证,我不在乎他们使用什么标准和版本,但和其他人一样,我只相信他们的身份验证。 身份验证 基本上 验证他们声称自己是谁。 授权是对用户可以做什么/在哪里执行/转到的访问控制。内部访问控制(允许用户做什么)没有暴露给谷歌他们不知道。所以 accessToken 应该不在图片中。正确的?

https://i.stack.imgur.com/Mebpg.png

因此,我的情况的解决方案是

使用 Google 的身份验证。

在初始验证 idToken 后,在 API 上创建自己的会话管理/超时规则以减轻 exp。

最好使用 res.cookie("SESSIONID", myOwnID, {httpOnly:true, secure:true}) 将此会话数据添加到 cookie 中;

为了更好的保护,Eiji 还推荐了Cross Account Protection。希望这会对某人有所帮助!


关注公众号,不定期副业成功案例分享
关注公众号

不定期副业成功案例分享

领先一步获取最新的外包任务吗?

立即订阅