You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

关于OpenID Connect中expires_in与expires_at差异的技术问询

理解expires_in与expires_at的差异:OIDC规范 vs ASP.NET Core/IdentityServer4实现

你的困惑其实源于两个不同层面的概念:OIDC协议规范定义的字段,和ASP.NET Core身份验证系统的本地存储约定。咱们一步步拆解:

1. expires_in:OIDC Token Response的标准字段

根据OpenID Connect规范,expires_in是令牌端点返回的相对有效期(以秒为单位),表示从令牌发放时刻开始,访问令牌多久后过期。这是协议层面要求返回给客户端的字段,所以你用tokenClient.RequestRefreshTokenAsync拿到的tokenResult.ExpiresIn属性,正是对这个规范字段的映射——这部分完全符合OIDC标准,没有问题。

2. expires_at:ASP.NET Core身份系统的本地存储约定

而代码里存入AuthenticationToken的expires_at,是ASP.NET Core和IdentityServer4在本地维护身份验证票据时的自定义字段,它存储的是令牌过期的绝对UTC时间(格式为ISO 8601)。

这么设计的原因很实际:

  • 当你需要判断当前身份票据是否有效时,直接对比expires_at和当前UTC时间即可,不用每次都用当前时间加上expires_in去计算过期时间,更高效。
  • 这个字段只存在于本地的身份验证票据中,并不是访问令牌(JWT)本身的内容——JWT里的过期信息是通过exp声明(Unix时间戳)来体现的,这才是OIDC规范要求JWT必须包含的过期标识。

3. 代码逻辑的合理性

你的代码片段做的事情,正是把OIDC返回的相对有效期(expires_in)转换成了本地存储用的绝对时间(expires_at):

var tokenResult = await tokenClient.RequestRefreshTokenAsync(currentRefreshToken);
var expiresAt = DateTime.UtcNow + TimeSpan.FromSeconds(tokenResult.ExpiresIn);
updatedTokens.Add(new AuthenticationToken { Name = "expires_at", Value = expiresAt.ToString("o", CultureInfo.InvariantCulture) });

这是IdentityServer4集成ASP.NET Core身份系统的常规操作,目的是在本地缓存中维护票据的过期时间,方便后续的身份验证流程使用。

关键澄清

  • 你提到的"JWT实际实现未遵循规范"其实是误解:expires_in是Token Response的字段,不是JWT的一部分;JWT本身的exp声明才是规范要求的过期标识,IdentityServer4生成的JWT肯定包含这个声明。
  • expires_at确实是针对整个身份验证票据(AuthenticationTicket)的存储字段,和访问令牌本身是两个层面的东西——令牌是发给客户端的凭证,而票据是ASP.NET Core在本地维护的用户身份会话信息。

内容的提问来源于stack exchange,提问作者SpiritBob

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 09:18:16