Mensagem de erro
Unexpected registration response origin "http://localhost:3000", expected "https://app.example.com"
Também aparece como
- Unexpected authentication response origin "http://localhost:3000", expected "https://app.example.com"
- Unexpected registration response challenge "b3RoZXI", expected "c2VydmVyLWNoYWxsZW5nZS0xMjM"
O primeiro valor entre aspas é a origem que o navegador informou; o segundo, a sua configuração. Durante o login, o texto diz “authentication response”; um desafio divergente produz “Unexpected registration response challenge …” na mesma biblioteca.
SimpleWebAuthn (@simplewebauthn/server) — verifyRegistrationResponse / verifyAuthenticationResponse
O que significa
O navegador registrou a origem da página em `clientDataJSON` (os dados que o autenticador assina), e ela difere do `expectedOrigin` que seu servidor passou ao SimpleWebAuthn. Essa verificação existe para impedir que uma cerimônia de credencial realizada em um site — por exemplo, uma imitação usada em phishing — seja aceita por outro. Não há nada de errado com o autenticador; o que o servidor entende como o endereço das próprias páginas não corresponde ao lugar onde a cerimônia realmente ocorreu.
Por que acontece
Origem de produção configurada em desenvolvimento (ou o contrário)
comum`expectedOrigin` fixado no código com a URL de produção enquanto os testes rodam em `http://localhost:3000`, em um deploy de preview ou na URL de um túnel (ngrok, Cloudflare Tunnel).
A página de login é servida a partir de várias origens
comum`www.` e o domínio apex, vários domínios de país ou um subdomínio `accounts.` separado. Toda origem que possa executar a cerimônia precisa estar na lista.
Um app Android nativo
ocasionalO Gerenciador de credenciais (Credential Manager) informa `android:apk-key-hash:…` como origem, e não a sua origem web. O hash da chave de assinatura do app precisa estar em `expectedOrigin`.
Como corrigir
- 1.
Listar explicitamente todas as origens legítimas
`expectedOrigin` aceita um array. Inclua só origens que você controla; nunca aceite a origem vinda da própria requisição.
js const verification = await verifyRegistrationResponse({ response: body, expectedChallenge: session.currentChallenge, // Every origin that legitimately hosts your sign-up page, exactly as browsers report it: expectedOrigin: ["https://app.example.com", "https://www.example.com"], expectedRPID: "example.com", }); - 2.
Adicionar a origem do app Android
Calcule o SHA-256 em base64url do certificado de assinatura do app e adicione-o no formato `android:apk-key-hash:`.
js // Android apps report "android:apk-key-hash:<base64url SHA-256 of the app signing certificate>". // SHA-256 fingerprint from Play Console or: keytool -list -v -keystore release.jks | grep SHA256 const fingerprintHex = process.env.ANDROID_SIGNING_CERT_SHA256.replaceAll(":", ""); const androidOrigin = "android:apk-key-hash:" + Buffer.from(fingerprintHex, "hex").toString("base64url"); const verification = await verifyRegistrationResponse({ response: body, expectedChallenge: session.currentChallenge, expectedOrigin: ["https://example.com", androidOrigin], expectedRPID: "example.com", });