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

WebAuthn技术疑问:调用credentials.get能否获取Passkey的公钥?

WebAuthn Passkey 存储失败后的PublicKey缺失问题处理

问题核心

调用credential.create生成Passkey时,返回的attestationObject里包含CBOR格式的PublicKey;但调用credential.get做登录验证时,仅能拿到authenticatorData,不会返回PublicKey。

如果创建Passkey过程中出现网络故障,后端存储PublicKey的请求失败,但Passkey已经在用户设备上创建完成,后续用户登录时就会因为后端没有对应的PublicKey,无法验证签名,导致登录失败。目前WebAuthn官方文档里没有针对这个场景的现成解决方案。

可行解决方案

1. 前端本地临时缓存待同步的PublicKey

  • 在credential.create成功后,先从attestationObject里解析出PublicKey,存在前端本地存储(比如localStorage),同时给该凭证标记「未完成后端同步」的状态。
  • 后续每次页面加载、或者用户触发登录操作前,先检查本地有没有未同步的PublicKey,自动尝试重新向后端发送存储请求,直到同步成功再清除本地缓存。

2. 保证Passkey创建与后端存储的原子性

  • 调整流程:调用credential.create前,先向后端发起「预创建请求」,获取一个唯一的syncToken。
  • 创建Passkey成功后,携带syncToken和解析后的PublicKey一起发送后端存储请求,后端通过syncToken确保该Passkey的唯一性,避免重复创建。如果存储失败,前端可以用同一个syncToken重试,不用重新生成Passkey。

3. 尝试清理设备上的无效Passkey

  • 部分现代浏览器支持PublicKeyCredential.delete()方法,可以删除已创建的Passkey。如果后端存储失败,前端可以尝试调用这个方法删除设备上的无效凭证,避免遗留垃圾数据。
  • 示例代码:
    // 传入要删除的凭证ID(Uint8Array格式)
    const deleteConfig = {
      publicKey: {
        excludeCredentials: [{
          type: "public-key",
          id: targetCredentialId
        }]
      }
    };
    try {
      await PublicKeyCredential.delete(deleteConfig);
    } catch (err) {
      // 删除失败时,提示用户手动清理浏览器中的Passkey
    }
    

请求响应示例

credential.create 请求与响应

请求代码:

const createOpts = {
  publicKey: {
    rp: { name: "你的应用名称" },
    user: {
      id: new Uint8Array(16),
      name: "user@yourdomain.com",
      displayName: "用户昵称"
    },
    challenge: new Uint8Array(32),
    pubKeyCredParams: [{ type: "public-key", alg: -7 }]
  }
};
const newCredential = await navigator.credentials.create(createOpts);

从响应中解析PublicKey:

// 需要引入CBOR解析库,比如cbor-js
const attestationData = CBOR.decode(new Uint8Array(newCredential.response.attestationObject));
const publicKey = attestationData.authData.publicKey;

credential.get 请求与响应

请求代码:

const getOpts = {
  publicKey: {
    challenge: new Uint8Array(32),
    allowCredentials: [{ type: "public-key", id: credentialIdBuffer }]
  }
};
const assertion = await navigator.credentials.get(getOpts);

响应仅包含authenticatorData:

const authData = new Uint8Array(assertion.response.authenticatorData);
// 此处无法获取到PublicKey

内容的提问来源于stack exchange,提问作者Ильсур Ибрагимов

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 06:55:33