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

NestJS JwtService验证JWT时读取错误nbf日期问题

问题:NestJS JwtService验证JWT时抛出NotBeforeError错误

问题重现

JWT初始化代码

import { JwtModule } from '@nestjs/jwt';
// ...
JwtModule.register({
    secret: 'mysecret', // TODO: 生产环境改用注入值
    signOptions: { expiresIn: '1h' },
}),

JWT签名代码

import { JwtService, JwtSignOptions } from '@nestjs/jwt';

// ...

constructor(
    private readonly jwtService: JwtService,
) {}

// ...

const userInfo = {
    email: user.email,
    firstName: user.firstName,
    lastName: user.lastName
};
const accessTokenPayload = {
    iss: 'Auth Server 3.2',     // 签发者
    sub: user.id.toString(),    // 主题(用户ID)
    aud: ['myClient'],          // 受众(接收方)
    exp: (new Date()).getTime() + 24 * 60 * 60 * 1000,  // 过期时间(毫秒级时间戳)
    nbf: (new Date()).getTime() - 60 * 60 * 1000,
    iat: new Date().getTime(),              // 签发时间(毫秒级时间戳)
    jti: randomBytes(32).toString('hex'),   // JWT唯一标识
    data: { userInfo }
}
const accessToken = await this.jwtService.signAsync(accessTokenPayload);

验证代码及错误

try {
    await this.jwtService.verifyAsync(accessToken);
} catch(e) {
    console.log('Error', e)
}

抛出错误:

Error NotBeforeError {
        name: 'NotBeforeError',
        message: 'jwt not active',
        date: +055303-05-11T16:49:49.000Z  // 注意这里的nbf解析出了错误的未来日期
}

问题原因

JWT标准中,nbf(生效时间)、exp(过期时间)、iat(签发时间)字段要求的是Unix秒级时间戳,但你使用new Date().getTime()获取的是毫秒级时间戳(13位数字)。

验证时,@nestjs/jwt底层依赖的jsonwebtoken库会把这个毫秒数当成秒数解析,相当于把实际时间放大了1000倍,原本的2023年被解析成了55303年,自然会抛出"jwt not active"错误。

解决方案

方案1:手动将毫秒时间戳转为秒级

把所有时间字段的值除以1000并取整,转换成符合标准的秒级时间戳:

const currentTime = Math.floor(Date.now() / 1000); // 转成秒级时间戳
const accessTokenPayload = {
    iss: 'Auth Server 3.2',
    sub: user.id.toString(),
    aud: ['myClient'],
    exp: currentTime + 24 * 60 * 60, // 24小时后过期(秒)
    nbf: currentTime - 60 * 60, // 1小时前生效(秒)
    iat: currentTime,
    jti: randomBytes(32).toString('hex'),
    data: { userInfo }
}
const accessToken = await this.jwtService.signAsync(accessTokenPayload);

方案2:让JwtService自动处理标准时间字段

推荐使用这种方式,避免手动处理时间戳的错误。在JwtModule注册时配置默认参数,签名时只传递业务相关数据:

// JWT模块初始化
JwtModule.register({
    secret: 'mysecret',
    signOptions: { 
        expiresIn: '24h', // 自动设置exp字段
        notBefore: '-1h', // 自动设置nbf字段(允许1小时前生效)
        issuer: 'Auth Server 3.2', // 自动设置iss字段
        audience: ['myClient'] // 自动设置aud字段
    },
}),

// 签名代码
const accessTokenPayload = {
    sub: user.id.toString(),
    jti: randomBytes(32).toString('hex'),
    data: { userInfo }
}
const accessToken = await this.jwtService.signAsync(accessTokenPayload);

此时JwtService会自动生成符合标准的iat、nbf、exp字段,无需手动计算时间戳。


内容的提问来源于stack exchange,提问作者Lorraine Ram-El

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 07:25:00