jsonwebtoken (Node.js)JWT 库
错误信息
jwt expired
含义
这是 jsonwebtoken 的 TokenExpiredError:令牌的 exp 声明(以秒为单位的 Unix 时间戳)早于验证方时钟的当前时间。签名本身可能完全有效——只是令牌已经超过了颁发者赋予它的有效期。错误对象的 expiredAt 中记录了确切的过期时刻。
原因
令牌确实已过期
常见短期有效的访问令牌(5~60 分钟)是常态;缓存令牌并在之后重复使用的客户端,或者在长时间运行期间一直持有同一令牌的后台任务,都会准时遇到这个错误。解决办法是实现刷新流程,而不是延长有效期。
颁发者与验证方之间的时钟偏差
常见如果验证服务器的时钟快于颁发者的时钟,令牌就会提前“过期”——有时一签发就过期。没有 NTP 的容器和虚拟机,时钟漂移得出奇地快;两分钟的偏差就足以让有效期不到一小时的令牌间歇性失效。
exp 的单位写错了
偶见规范(RFC 7519)规定 exp 以秒为单位。多除了一次 1000 的代码会生成 1970年的时间戳,让每个令牌一签发就过期。相反的失误——把 Date.now()(毫秒)写入 exp——根本不会触发这个错误:它生成的时间戳在 56,000 多年之后,令牌永远不会过期。
修复方法
- 1.
显式允许少量时钟偏差
clockTolerance 接受秒数,同时作用于 exp 和 nbf。把它设得小一些(30~60 秒)——它用于吸收时钟漂移,而不是延长令牌的有效期。
js jwt.verify(token, publicKey, { algorithms: ["ES256"], clockTolerance: 30, // seconds of tolerated skew }); - 2.
先检查 exp,再怀疑时钟
解码声明,把 exp 与当前时间并排打印。如果 exp 看起来像 1.7e12,说明存在毫秒单位错误;如果它在几分钟之前,你需要的是刷新逻辑。
js const { exp } = jwt.decode(token); console.log("exp:", new Date(exp * 1000).toISOString()); console.log("now:", new Date().toISOString()); - 3.
同步时钟并添加刷新机制
在负责验证的主机上运行 NTP(chrony/systemd-timesyncd),并在客户端实现收到 401 响应时刷新令牌。切勿把 ignoreExpiration: true 发布到生产环境——它会让每个泄露的令牌都变成永久有效的凭证。