使用SimpleWebAuthn、React和Node.js实现PassKey认证时遇解码错误
PassKey认证失败:
verifyAuthenticationResponse调用报错排查 尝试使用PassKey实现用户认证时,调用verifyAuthenticationResponse方法无法完成登录,服务器抛出意外错误。曾怀疑MongoDB存储的数据格式问题,转换为普通JS对象后问题仍未解决,MongoDB中passkey字段类型为Mixed。
相关代码
exports.loginVerification = async (req, res) => { try { const { username, credential } = req.body; if (!username || !credential) { return res.status(400).json({ status: "fail", message: "Username and credential are required", }); } const user = await User.findOne({ username }).select("-password"); if (!user) { return res.status(404).json({ status: "fail", message: "User not found", }); } const challenge = await Challenge.findOne({ userId: user._id }); if (!challenge) { return res.status(404).json({ status: "fail", message: "Challenge not found", }); } const userObject = user.toObject(); const credentialId = userObject.passkey.credentialID; const credentialPublicKey = userObject.passkey.credentialPublicKey; const counter = userObject.passkey.counter; console.log({ passkey: userObject.passkey, }); const result = await verifyAuthenticationResponse({ expectedOrigin: process.env.ORIGIN, expectedRPID: process.env.RP_ID, response: credential, expectedChallenge: challenge.challenge, authenticator: userObject.passkey, }); console.log({ result }); if (!result.verified) { return res.status(401).json({ status: "fail", message: "Verification failed", }); } res.status(200).json({ status: "success", verified: result.verified, message: "Verification successful", user, }); } catch (error) { console.log(error); res.status(400).json({ status: "fail", message: error.message, }); } };
错误栈信息
Error: No data at Object.decodePartialCBOR (D:\fullstack\passkey-authentication\server\node_modules\@levischuck\tiny-cbor\script\cbor\cbor.js:355:15) at Object.decodeFirst (D:\fullstack\passkey-authentication\server\node_modules\@simplewebauthn\server\script\helpers\iso\isoCBOR.js:25:40) at decodeCredentialPublicKey (D:\fullstack\passkey-authentication\server\node_modules\@simplewebauthn\server\script\helpers\decodeCredentialPublicKey.js:6:84) at verifySignature (D:\fullstack\passkey-authentication\server\node_modules\@simplewebauthn\server\script\helpers\verifySignature.js:20:86) at verifyAuthenticationResponse (D:\fullstack\passkey-authentication\server\node_modules\@simplewebauthn\server\script\authentication\verifyAuthenticationResponse.js:157:66) at async exports.loginVerification (D:\fullstack\passkey-authentication\server\controllers\challenge.controller.js:182:20)
响应输出

问题原因及解决办法
原因分析
错误栈指向CBOR解码失败(No data),核心问题是存储在MongoDB中的credentialPublicKey格式不符合@simplewebauthn/server的要求。PassKey的公钥是CBOR编码的二进制数据,需要以Buffer类型传入验证函数,但MongoDB的Mixed类型可能将原始Buffer转成了Base64字符串、MongoDB Binary对象或其他格式,导致解码时无法识别有效数据。
解决步骤
- 检查存储格式:查看MongoDB中
passkey.credentialPublicKey的实际存储形式——如果是Base64字符串、十六进制字符串或MongoDB Binary对象,需要转换为Node.js Buffer类型。 - 修改代码转换格式:在获取用户passkey数据后,手动将
credentialID和credentialPublicKey转换为Buffer,再构造符合要求的authenticator对象:
// 替换原passkey字段处理逻辑 const userObject = user.toObject(); // 根据实际存储格式转换,这里假设是Base64字符串 const credentialId = Buffer.from(userObject.passkey.credentialID, 'base64'); // 公钥必须是Buffer类型才能被CBOR解码 const credentialPublicKey = Buffer.from(userObject.passkey.credentialPublicKey, 'base64'); const counter = userObject.passkey.counter; const transports = userObject.passkey.transports || []; // 构造符合@simplewebauthn/server要求的authenticator对象 const authenticator = { credentialID: credentialId, credentialPublicKey: credentialPublicKey, counter: counter, transports: transports, }; // 调用验证函数时传入转换后的authenticator const result = await verifyAuthenticationResponse({ expectedOrigin: process.env.ORIGIN, expectedRPID: process.env.RP_ID, response: credential, expectedChallenge: challenge.challenge, authenticator: authenticator, });
- 验证存储逻辑:确保用户注册时,
credentialPublicKey是以原始Buffer或可正确反序列化为Buffer的格式存入MongoDB(避免自动转换为字符串)。
内容的提问来源于stack exchange,提问作者Varshil Shah
相关产品推荐
相关产品推荐

