错误信息
SecurityError: The relying party ID is not a registrable domain suffix of, nor equal to the current domain. Subsequently, an attempt to fetch the .well-known/webauthn resource of the claimed RP ID failed.
也可能输出为
- SecurityError: The relying party ID is not a registrable domain suffix of, nor equal to the current domain.
不支持相关源请求的 Chromium 版本,句子在“…nor equal to the current domain.”之后就结束了。其他浏览器的措辞不同;DOMException 名称 `SecurityError` 是固定不变的部分。
WebAuthn navigator.credentials.create() / get() — DOMException SecurityError (Chromium)
含义
你在选项中设置的 RP ID 既不是页面自身的主机名,也不是它的可注册上级域名,因此浏览器拒绝为它创建或使用凭证。通行密钥绑定在其 RP ID 上;如果任何页面都能声称任意 RP ID,一个站点就能使用另一个站点的通行密钥。Chromium 还尝试了 WebAuthn 相关源请求(Related Origin Requests)机制(获取 `https://<rp-id>/.well-known/webauthn`,查看该 RP ID 是否列出了你的源),但这也没有让请求获得授权。
原因
在开发或预览主机上使用了生产环境的 RP ID
常见把 `rp.id: "app.example.com"` 发给了位于 `localhost`、预览部署 URL(`*.vercel.app`、`*.netlify.app`)或预发布域名上的页面。RP ID 必须与提供该页面的环境相匹配。
把同级域名或子域名用作 RP ID
常见`login.example.com` 上的页面可以使用 `login.example.com` 或 `example.com`,但不能使用 `app.example.com` 或 `api.login.example.com`。一开始就选择上级域名,所有子域名就能共享通行密钥。
另一个域名缺少 .well-known/webauthn 条目
偶见要在不同域名之间(各国家/地区的顶级域名、品牌更名后的域名)使用同一个 RP ID,RP ID 所在的域名必须在 `/.well-known/webauthn` 中列出其他源。如果没有这个文件,或者文件无法访问,请求就会被拒绝。
通过 IP 地址打开网站
偶见IP 地址不是有效的 RP ID;WebAuthn 需要域名(开发时允许使用 `localhost`)。
修复方法
- 1.
按环境配置 RP ID
把 RP ID 和预期的源一起放在环境配置中,让开发、预览和生产环境各自使用自己的主机——并且记住,通行密钥不会在不同的 RP ID 之间迁移。
js // Server: derive the RP ID from configuration per environment, never hard-code production. const rpID = process.env.WEBAUTHN_RP_ID; // "localhost" in dev, "example.com" in production const expectedOrigin = process.env.WEBAUTHN_ORIGIN; // "http://localhost:3000" / "https://app.example.com" const options = await generateRegistrationOptions({ rpName: "Example", rpID, userName }); - 2.
明确发布相关源
如果你的多个域名必须共享通行密钥,就在 RP ID 所在的域名上提供 `/.well-known/webauthn`,并在其中列出这些域名(当前的 Chromium 和 Safari 支持这一机制)。
json // https://example.com/.well-known/webauthn (served as application/json) { "origins": ["https://example.co.uk", "https://example-shop.com"] }
相关错误
NotAllowedError: The operation either timed out or was not allowed. See: https:…WebAuthn navigator.credentials.get() / create()Unexpected registration response origin "http://localhost:3000", expected "http…SimpleWebAuthn (@simplewebauthn/server)TypeError: Cannot read properties of undefined (reading 'digest')WebCrypto