Mensaje de error
Unexpected registration response origin "http://localhost:3000", expected "https://app.example.com"
También se muestra como
- Unexpected authentication response origin "http://localhost:3000", expected "https://app.example.com"
- Unexpected registration response challenge "b3RoZXI", expected "c2VydmVyLWNoYWxsZW5nZS0xMjM"
El primer valor entre comillas es el origen que indicó el navegador; el segundo, tu configuración. Durante el inicio de sesión, el texto dice «authentication response»; un desafío que no coincide produce «Unexpected registration response challenge …» en la misma biblioteca.
SimpleWebAuthn (@simplewebauthn/server) — verifyRegistrationResponse / verifyAuthenticationResponse
Qué significa
El navegador guardó el origen de la página en `clientDataJSON` (los datos que firma el autenticador), y ese origen no coincide con el `expectedOrigin` que tu servidor pasa a SimpleWebAuthn. La comprobación existe para impedir que un sitio acepte una ceremonia de credenciales realizada en otro, por ejemplo, en una imitación creada para phishing. El autenticador no tiene ningún problema: lo que el servidor cree sobre dónde están sus páginas no coincide con el lugar donde se ejecutó realmente la ceremonia.
Por qué ocurre
Origen de producción configurado en desarrollo (o al revés)
frecuente`expectedOrigin` fijado en el código a la URL de producción mientras pruebas en `http://localhost:3000`, en un despliegue de vista previa o en la URL de un túnel (ngrok, Cloudflare Tunnel).
La página de inicio de sesión se sirve desde varios orígenes
frecuente`www.` y el dominio raíz, varios dominios por país o un subdominio `accounts.` aparte. Hay que incluir en la lista cada origen que pueda ejecutar la ceremonia.
Una aplicación nativa de Android
ocasionalCredential Manager indica `android:apk-key-hash:…` como origen, no tu origen web. El hash de la clave de firma de la aplicación tiene que estar en `expectedOrigin`.
Cómo solucionarlo
- 1.
Enumerar explícitamente todos los orígenes legítimos
`expectedOrigin` acepta un array. Limítalo a orígenes que controlas; nunca aceptes el origen que viene en la propia solicitud.
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.
Añadir el origen de la aplicación Android
Calcula el SHA-256 en base64url del certificado de firma de la aplicación y añádelo con la forma `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", });