Node.js中Twilio Authy App无法生成匹配的正确TOTP验证码
TOTP生成验证码与Authy不匹配问题排查
问题场景
使用otplib实现TOTP验证码生成、校验逻辑时,本地生成的验证码始终无法和Authy等主流TOTP认证应用输出的验证码匹配,已确认otplib包本身可正常生成验证码,初步怀疑故障点为密钥格式非法或TOTP配置与应用不匹配。
参考实现代码如下:
const generateSecretKey = (size=16) => { const val = crypto.randomBytes(size).toString('hex').slice(0, size).toUpperCase() return val; } const generateTotp = (secret) => { const token = totp.generate(secret) return token; } const authChallenge = (token, secret) =>{ const isValid = totp.check(token, secret); return isValid } let secret = generateSecretKey() console.log("secret => " + secret) let token = generateTotp(secret) console.log(`generateTotp => token ${token}`) let authChallengeResponse = authChallenge(token, secret)
代码运行结果参考:
故障原因
故障是两个问题共同导致的:
- 密钥格式不符合标准:当前逻辑生成的是HEX格式密钥,而Authy、Google Authenticator等通用TOTP应用仅支持RFC6238标准规定的Base32编码格式密钥,密钥解码规则不匹配会直接导致最终计算出的验证码完全不同。
- TOTP配置未对齐通用应用默认值:直接使用
totp实例的默认配置时,部分版本的otplib默认哈希算法、时间步长、验证码位数和通用TOTP应用的默认参数不一致,也会导致验证码不匹配。
修复方案
直接使用otplib内置的authenticator实例,该实例的默认参数完全对齐主流TOTP认证应用的实现标准,同时内置了标准Base32密钥生成方法,无需手动实现编码逻辑。
修复后可直接运行的代码如下:
const { authenticator } = require('otplib'); // 生成符合标准的Base32格式密钥,可直接输入Authy等应用使用 const generateSecretKey = () => { return authenticator.generateSecret(); } const generateTotp = (secret) => { // 显式锁定配置,避免不同版本默认值差异导致故障 authenticator.options = { algorithm: 'sha1', digits: 6, step: 30, window: 1 // 校验时允许前后1个时间窗口的误差,适配设备间时间差 } return authenticator.generate(secret); } const authChallenge = (token, secret) =>{ return authenticator.check(token, secret); } // 功能测试 const secret = generateSecretKey() console.log("标准TOTP密钥 => " + secret) const token = generateTotp(secret) console.log(`本地生成验证码 => ${token}`) const checkResult = authChallenge(token, secret) console.log("本地校验结果 => ", checkResult)
额外注意事项
- 向Authy录入密钥时,不要添加多余空格、特殊字符,Base32编码不区分大小写,直接输入生成的字符串即可。
- 如果修复后仍校验失败,先检查运行代码的服务端/本地设备,和安装Authy的手机设备的系统时间差是否超过30秒,时间不同步是TOTP校验失败的高频原因。
内容的提问来源于stack exchange,提问作者JavascriptDeveloperMaintwo
相关产品推荐
相关产品推荐

