Aprende a configurar pruebas E2E para passkeys en diferentes navegadores con Playwright, Nightwatch, Selenium y Puppeteer utilizando el autenticador virtual WebAuthn.
Anders
Created: June 17, 2025
Updated: June 20, 2025
Nuestra misión es hacer de Internet un lugar más seguro, y el nuevo estándar de login, las passkeys, proporciona una solución superior para lograrlo. Por eso queremos ayudarte a comprender mejor las passkeys y sus características.
Las passkeys son cada vez más aceptadas como método de autenticación, basándose en la Autenticación Web (WebAuthn) como su estándar subyacente. Su aumento de popularidad es bastante reciente, lo que hace que la documentación y otros recursos sean relativamente escasos. Esto, junto con la naturaleza compleja de la implementación de passkeys, puede dificultar que los desarrolladores encuentren información relevante sobre el diseño, la implementación y, especialmente, las pruebas de passkeys para sus plataformas y servicios.
Esta guía tiene como objetivo llenar ese vacío, centrándose en aspectos del autenticador virtual WebAuthn que no se tratan a fondo en su documentación oficial. Por ejemplo, discutimos opciones de configuración para el autenticador virtual que no son autoexplicativas en la documentación, así como soluciones para ciertos casos de uso para los que el autenticador virtual no proporciona una solución conveniente. Además, esta guía también es útil para los desarrolladores que simplemente buscan ejemplos fáciles de seguir para usar el autenticador virtual en el código de prueba.
Nuestra guía utiliza ejemplos de Playwright para proporcionar un recorrido sencillo para probar eficazmente la implementación de passkeys en tu proyecto. Playwright es un marco de pruebas de extremo a extremo (E2E) que utiliza el Protocolo de Herramientas para Desarrolladores de Chrome (CDP) como protocolo para la automatización de navegadores. Si buscas específicamente ejemplos técnicos de pruebas de passkeys en Playwright, puedes saltar a la Sección 5. Por otro lado, si estás utilizando otros marcos de pruebas E2E como Puppeteer o Selenium y buscas probar passkeys en estos marcos, las implementaciones del código de prueba serán idénticas o muy similares a los ejemplos proporcionados en esta guía, dependiendo del marco que estés utilizando. En la siguiente sección, proporcionamos un contexto sobre los diferentes marcos E2E y cuán relevante será esta guía para estos marcos.
Recent Articles
📖
Passkeys en aplicaciones nativas: Implementación nativa frente a WebView
👤
Resolución de problemas con passkeys: Soluciones para incidencias y errores
👤
Cómo habilitar las passkeys en Windows
⚙️
Tutorial de Passkeys: Cómo Implementar Passkeys en Aplicaciones Web
⚙️
Pruebas E2E de Passkeys con Playwright mediante el Autenticador Virtual WebAuthn
La automatización de navegadores, como su nombre indica, es el proceso de automatizar acciones repetitivas del usuario en el navegador con el fin de extraer datos de la web o, en nuestro caso, probar aplicaciones web. WebDriver y el Protocolo de Herramientas para Desarrolladores de Chrome (CDP) son dos de los principales protocolos de automatización de navegadores relevantes para esta guía, ya que cada uno proporciona una implementación del autenticador virtual WebAuthn.
WebDriver es una interfaz de control remoto que puede verse como un intermediario en la comunicación entre el cliente y el navegador. El enfoque de este protocolo es proporcionar una interfaz neutral en cuanto a plataforma e idioma que admita todos los principales navegadores, incluidos los que no están basados en Chromium, como Firefox y Safari. Como la interfaz de WebDriver necesita gestionar una conexión tanto con el cliente como con el navegador, este enfoque sacrifica velocidad y estabilidad a cambio de un mayor soporte de navegadores (es decir, mayor inestabilidad o flakiness). Clientes notables de WebDriver incluyen Selenium y Nightwatch.
Tomado de jankaritech
El Protocolo de Herramientas para Desarrolladores de Chrome (CDP), por otro lado, no tiene un intermediario como la interfaz de WebDriver entre el cliente y el navegador. Además, la comunicación entre el cliente y el navegador se realiza a través de una conexión de socket, en contraste con la conexión HTTP más lenta entre el cliente y la interfaz de WebDriver en el enfoque anterior. Estos puntos hacen que el CDP sea mucho más rápido y menos propenso a fallos (flaky) que WebDriver. La desventaja es que este protocolo solo es compatible con navegadores basados en Chromium como Chrome y Edge. Playwright y Puppeteer son ejemplos de clientes que utilizan CDP para comunicarse con los navegadores.
Tomado de jankaritech
Puppeteer, al igual que Playwright, es un marco de pruebas E2E construido directamente sobre el CDP. Esto significa que tanto Puppeteer como Playwright utilizan la misma implementación del autenticador virtual WebAuthn y que la comunicación de la API utilizando el autenticador virtual WebAuthn a través de la conexión de socket también es idéntica.
Para demostrarlo, comparamos el código de prueba tanto en Playwright como en Puppeteer para llamar al método getCredentials, que devuelve una lista de todas las credenciales registradas en el autenticador virtual hasta el momento. También adjuntamos un simple detector de eventos para el evento credentialAdded, que se activa cuando una credencial de passkey se registra con éxito. No te dejes intimidar por los detalles de la implementación, ya que se explicarán en las secciones posteriores. Estos ejemplos son simplemente para demostrar cuán similares son las implementaciones entre los dos marcos.
Ben Gould
Head of Engineering
I’ve built hundreds of integrations in my time, including quite a few with identity providers and I’ve never been so impressed with a developer experience as I have been with Corbado.
Más de 10,000 desarrolladores confían en Corbado y hacen de Internet un lugar más seguro con passkeys. ¿Tienes preguntas? Hemos escrito más de 150 artículos de blog sobre passkeys.
Únete a la Comunidad de PasskeysPlaywright:
const client = await page.context().newCDPSession(page); await client.send('WebAuthn.enable'); const authenticatorId = const result = await client.send('WebAuthn.addVirtualAuthenticator', { options }); ... // get all credentials registered in the virtual authenticator const result = await client.send('WebAuthn.getCredentials', { authenticatorId }); console.log(result.credentials); // add a listener to the credentialAdded event to output a log to the console whenever a passkey credential is registered client.on('WebAuthn.credentialAdded', () => { console.log('Credential Added!'); });
Puppeteer:
const client = await page.target().createCDPSession(); await client.send('WebAuthn.enable'); const authenticatorId = const result = await client.send('WebAuthn.addVirtualAuthenticator', { options }); ... // get all credentials registered in the virtual authenticator const result = await client.send('WebAuthn.getCredentials', { authenticatorId }); console.log(result.credentials); // add a listener to the credentialAdded event to output a log to the console whenever a passkey credential is registered client.on('WebAuthn.credentialAdded', () => { console.log('Credential Added!'); });
Aunque los métodos para inicializar la sesión de CDP al principio de los códigos de prueba eran ligeramente diferentes, la llamada a métodos y el manejo de eventos en la API del autenticador virtual WebAuthn de CDP son idénticos. Esto significa que si buscas utilizar el autenticador virtual WebAuthn en Puppeteer, puedes seguir esta guía línea por línea.
Selenium y Nightwatch son marcos de pruebas E2E que dependen de WebDriver para la automatización de navegadores. Aunque la implementación del autenticador virtual WebAuthn para WebDriver es independiente de su implementación para CDP, sus especificaciones de API son similares. Para casi todos los métodos en la API del autenticador virtual WebAuthn de CDP, puedes encontrar un método correspondiente en la API del autenticador virtual WebAuthn de WebDriver. Sin embargo, una cosa a tener en cuenta es que, si bien era posible adjuntar detectores de eventos para cuando una passkey se agrega o se afirma con éxito en la API del autenticador virtual WebAuthn de CDP, esto no es posible en su contraparte de WebDriver.
Selenium:
const driver = await new Builder().forBrowser('chrome').build(); const options = new VirtualAuthenticatorOptions(); await driver.addVirtualAuthenticator(options); ... // get all credentials registered in the virtual authenticator const credentials = await driver.getCredentials();
Es evidente que la sintaxis para configurar la instancia del autenticador virtual y realizar llamadas a la API es diferente de la implementación de CDP correspondiente. Sin embargo, dado que las especificaciones de la API de los dos autenticadores virtuales WebAuthn son muy similares, sería viable seguir esta guía para escribir una implementación correspondiente en un marco de pruebas E2E basado en WebDriver.
Cypress es un marco de pruebas E2E que no se basa principalmente en WebDriver o CDP como los marcos mencionados anteriormente. Utiliza JavaScript nativo para comunicarse con el navegador. Sin embargo, proporciona acceso de bajo nivel al CDP, lo que significa que es posible enviar comandos CDP sin procesar para utilizar el autenticador virtual WebAuthn del CDP.
Debido a que la sintaxis para este acceso de bajo nivel es tediosa y muy diferente de los ejemplos anteriores, no entraremos en detalles en esta guía. Sin embargo, se explica más información sobre cómo llamar a los comandos de CDP en Cypress en esta guía. Los conceptos generales para usar el autenticador virtual WebAuthn de CDP presentados en esta guía siguen siendo relevantes para aquellos que buscan probar passkeys en Cypress.
Hay muchas razones por las que probar la implementación de passkeys es naturalmente más desafiante que otras acciones de usuario más simples en un entorno web. La necesidad de manejar interacciones dinámicas del usuario involucradas en la autenticación biométrica, como el escaneo de huellas dactilares o el reconocimiento facial, agrega una capa de complejidad que podría no ser práctica de abordar en detalle al escribir pruebas. Como la seguridad es naturalmente una preocupación importante en el contexto de la autenticación, también es necesario garantizar que la autenticación con passkeys se integre sin problemas en varios navegadores y dispositivos sin dejar lugar a vulnerabilidades de seguridad.
Simplificar la complejidad de manejar las interacciones dinámicas del usuario involucradas en las operaciones de passkeys, así como probar su integración en diferentes navegadores y dispositivos, se facilita con el uso del autenticador virtual WebAuthn.
El autenticador virtual WebAuthn es una representación de software del modelo de autenticador especificado en el estándar WebAuthn. Emula el comportamiento de un dispositivo autenticador físico, como una llave de seguridad de hardware (p. ej., YubiKey) o un escáner biométrico (p. ej., utilizado en Face ID, Touch ID o Windows Hello), pero opera completamente dentro del software (por lo que no hay autenticación física ni escaneo de datos biométricos involucrados).
Hay dos beneficios principales del autenticador virtual WebAuthn.
Como WebDriver y CDP son herramientas de automatización de navegadores, es evidente que el caso de uso principal de la implementación del autenticador virtual WebAuthn en estos protocolos son las pruebas automatizadas. Aprovechando estos protocolos, el autenticador virtual permite pruebas simples pero exhaustivas de las funcionalidades de las passkeys en entornos controlados, como los marcos de pruebas E2E (p. ej., Playwright, Cypress, Nightwatch).
El autenticador virtual WebAuthn del CDP también es accesible a través de las Herramientas para Desarrolladores (DevTools) del navegador Chrome, y puede usarse para pruebas manuales o simplemente con fines de demostración. Con esta función, puedes simular la entrada de una passkey en un dispositivo que no admite passkeys de forma nativa. De manera correspondiente, también es posible simular un entorno sin soporte para passkeys en un dispositivo que sí las admite.
La captura de pantalla anterior muestra un ejemplo del uso del autenticador virtual en Chrome para pruebas manuales o fines de demostración. Puedes ver que son posibles diferentes opciones de configuración para el autenticador virtual, y también se puede hacer un seguimiento de la adición y eliminación de credenciales. Consulta esta guía de Google para obtener más información sobre el uso del autenticador virtual en tu navegador, incluidas las opciones de configuración y los valores recomendados para cada una.
Si bien el autenticador virtual WebAuthn es una solución elegante para probar implementaciones de passkeys, hay algunas desventajas que vale la pena señalar.
Al ser una solución puramente basada en software, el autenticador virtual WebAuthn no puede replicar las características de hardware y las funciones de seguridad únicas de los autenticadores físicos. La distinción entre el uso de varios autenticadores de plataforma (que están integrados en un dispositivo, como un escáner biométrico en un teléfono inteligente) y varios autenticadores multiplataforma (que son dispositivos externos, como las llaves de seguridad de hardware) no se puede simular utilizando el autenticador virtual WebAuthn. Si bien la simplificación de caja negra de las complejidades involucradas con varios tipos de autenticadores de plataforma y multiplataforma es una de las ventajas de usar el autenticador virtual WebAuthn, si buscas simular y probar los matices de los diferentes tipos de autenticadores, se deben explorar otras soluciones.
Dada la adopción relativamente reciente de WebAuthn y la novedad de la tecnología de passkeys, el ecosistema que rodea a los autenticadores virtuales aún está madurando. Esto resulta en una escasez de documentación completa y desafíos técnicos no resueltos, particularmente en el contexto de la integración de autenticadores virtuales con marcos de pruebas automatizadas. Esta guía tiene como objetivo abordar este problema proporcionando información completa sobre las pruebas de passkeys en un entorno de pruebas automatizado, al tiempo que se centra en abordar los inconvenientes aún presentes en el uso de estas herramientas y presentar soluciones para estos problemas.
Después de una instalación exitosa de Playwright y sus dependencias, puedes comenzar de inmediato a escribir tu primera prueba creando un archivo con un nombre que termine en .spec.ts o .test.ts con el siguiente contenido:
import { test, expect } from "@playwright/test"; test("my first test", async ({ page }) => { await page.goto("https://passkeys.eu"); // start simulating user actions });
Para usar el autenticador virtual WebAuthn en Playwright, es suficiente con iniciar una sesión de CDP y adjuntar un autenticador virtual al principio de un caso de prueba, de la siguiente manera:
test('signup with passkey', async ({ page }) => { // Initialize a CDP session for the current page const client = await page.context().newCDPSession(page); // Enable WebAuthn environment in this session await client.send('WebAuthn.enable'); // Attach a virtual authenticator with specific options const result = await client.send('WebAuthn.addVirtualAuthenticator', { options: { protocol: 'ctap2', transport: 'internal', hasResidentKey: true, hasUserVerification: true, isUserVerified: true, automaticPresenceSimulation: false, }, }); const authenticatorId = result.authenticatorId; // Further test steps to simulate user interactions and assertions ... });
Opciones para configurar el autenticador virtual WebAuthn:
true
admite
Resident Key (es decir,
credencial detectable del lado del cliente).true
admite la verificación de usuario. Se
recomienda establecer esto como true
ya que permite la simulación de entradas de
passkey exitosas y fallidas.true
emula un escenario de autenticación exitoso,
mientras que false
imita un fallo de autenticación, como cuando un usuario cancela la
entrada de la passkey. Ten en cuenta que esta configuración solo es efectiva cuando
hasUserVerification
está establecido en true
.true
, la entrada de la passkey
ocurre de forma automática e inmediata ante cualquier solicitud de autenticación. Por el
contrario, establecerlo en false
requiere la iniciación manual de la simulación de
autenticación con passkey en el código de prueba. Se recomienda optar por la simulación
manual (false
) por dos razones:
En esta sección, exploramos el uso de los métodos y eventos del autenticador virtual WebAuthn en el contexto de casos de uso tanto comunes como marginales.
Esta podría ser la tarea más importante pero confusa al usar el autenticador virtual WebAuthn en un código de prueba, ya que no hay un método incorporado explícito para activar una entrada de passkey. La solución radica en las opciones de configuración del autenticador virtual WebAuthn, a saber, isUserVerified y automaticPresenceSimulation. Con estas opciones podemos simular esta interacción del usuario a través de dos enfoques diferentes que se describen a continuación.
Caso 1: Simulación de una entrada de passkey exitosa
test('signup with passkey', async ({ page }) => { ... await expect(page.getByRole('heading', { level: 1 })).toHaveText('Please log in'); await page.getByRole('button', { name: 'Login' }).click(); // successful passkey input is automatically simulated (isUserVerified=true) await expect(page.getByRole('heading', { level: 1 })).toHaveText('Welcome!'); ... });
Simular una entrada de passkey exitosa generalmente no requiere líneas adicionales en el código de prueba. La línea final (await expect...) espera a que la página cambie (desencadenada por la entrada de passkey exitosa implícita).
Caso 2: Simulación de una entrada de passkey cancelada (que no provoca cambios en la interfaz de usuario)
Probar una entrada de passkey fallida o cancelada es más complicado, ya que puede no conducir a ningún cambio observable en la interfaz de usuario. En otras palabras, esperar a que la página cambie como en el ejemplo anterior no es adecuado para garantizar que la entrada de la passkey haya completado el procesamiento. Comprobar que la página no ha cambiado después de la entrada implícita de la passkey no tiene sentido, ya que la comprobación casi con seguridad ocurrirá antes de que la entrada de la passkey haya completado el procesamiento. Si bien el autenticador virtual proporciona una forma de esperar a que se procese una entrada de passkey exitosa escuchando la emisión de eventos (como se discutirá en el enfoque 2), actualmente no hay una forma incorporada de detectar una entrada de passkey fallida o cancelada. Una solución sería simplemente agregar un tiempo de espera fijo para esperar a que se complete la operación de la passkey antes de verificar que la interfaz de usuario realmente se mantuvo igual.
test('signup with passkey', async ({ page }) => { // Simulate a set of user actions to trigger a passkey prompt ... await expect(page.getByRole('heading', { level: 1 })).toHaveText('Please log in'); // Simulate passkey input when prompted in the test await inputPasskey(async () => { await page.waitForTimeout(300); await expect(page.getByRole('heading', { level: 1 })).toHaveText('Please log in'); }); // Further test steps ... });
En cualquier caso, la legibilidad del código de prueba está limitada por la naturaleza implícita de la operación de la passkey. Como se mencionó anteriormente, también sería fácil pasar por alto cuándo se podría solicitar una UI condicional, en cuyo caso la operación de la passkey se completaría automáticamente sin el conocimiento del probador.
Activar manualmente una entrada de passkey cambiando el valor de la opción automaticPresenceSimulation resuelve los problemas encontrados en el enfoque anterior, especialmente en términos de legibilidad del código de prueba.
Caso 1: Simulación de una entrada de passkey exitosa
Los siguientes fragmentos de código simulan una entrada de passkey exitosa:
async simulateSuccessfulPasskeyInput(operationTrigger: () => Promise<void>) { // initialize event listeners to wait for a successful passkey input event const operationCompleted = new Promise<void>(resolve => { client.on('WebAuthn.credentialAdded', () => resolve()); client.on('WebAuthn.credentialAsserted', () => resolve()); }); // set isUserVerified option to true // (so that subsequent passkey operations will be successful) await client.send('WebAuthn.setUserVerified', { authenticatorId: authenticatorId, isUserVerified: true, }); // set automaticPresenceSimulation option to true // (so that the virtual authenticator will respond to the next passkey prompt) await client.send('WebAuthn.setAutomaticPresenceSimulation', { authenticatorId: authenticatorId, enabled: true, }); // perform a user action that triggers passkey prompt await operationTrigger(); // wait to receive the event that the passkey was successfully registered or verified await operationCompleted; // set automaticPresenceSimulation option back to false await client.send('WebAuthn.setAutomaticPresenceSimulation', { authenticatorId, enabled: false, }); }
test('signup with passkey', async ({ page }) => { ... // Simulate passkey input with a promise that triggers a passkey prompt as the argument await simulateSuccessfulPasskeyInput(() => page.getByRole('button', { name: 'Create account with passkeys' }).click() ); ... });
La función de ayuda puede ser bastante intimidante la primera vez que la ves. Ayuda a entender que todas las complejidades técnicas de simular una operación de passkey se abstraen en la función de ayuda. Esto significa que cuando se usa dentro del código de prueba, hace que el código sea simple y claro, como se puede ver en el segundo fragmento de código anterior.
En comparación con el enfoque implícito de la Sección 6.1.1, este enfoque explícito también aumenta la legibilidad del código. Esto sería especialmente útil para cuando se solicita una UI condicional, ya que este enfoque explícito evita la finalización implícita y no intencionada de la operación de la passkey sin que el desarrollador se dé cuenta.
Ahora entendamos cada parte de la función de ayuda.
Primero, definimos la promesa operationCompleted
que espera el evento
WebAuthn.credentialAdded
o el evento WebAuthn.credentialAsserted
, que, como su nombre
indica, se emite cuando una credencial de passkey se registra o verifica, respectivamente.
Esta promesa se usará más adelante.
A continuación, la opción isUserVerified
se establece en true
, para que la operación
de passkey posterior por parte del autenticador virtual WebAuthn sea exitosa. La
automaticPresenceSimulation
también se establece en true
, para que el autenticador
virtual WebAuthn responda a la siguiente solicitud de passkey de la página web.
La espera de la promesa operationTrigger
es necesaria para evitar una condición de
carrera. La condición de carrera ocurre cuando la página web solicita la passkey antes de
que automaticPresenceSimulation
se establezca en true
. Para evitar esto, la acción del
usuario que desencadena la solicitud de passkey debe realizarse después de que
automaticPresenceSimulation
se haya establecido en true
. En el ejemplo anterior, el
usuario hace clic en el botón llamado Create account with passkeys
para activar la
solicitud de passkey.
Una vez completada la acción del usuario, debemos esperar a que se complete la operación
de passkey exitosa. Esto se hace esperando la promesa que definimos al principio de la
función de ayuda. La finalización de la operación de passkey exitosa está marcada por la
emisión del evento WebAuthn.credentialAdded
o WebAuthn.credentialAsserted
. En el
ejemplo anterior, como el usuario está registrando una passkey, se emitiría el evento
WebAuthn.credentialAdded
.
Finalmente, la opción automaticPresenceSimulation
se vuelve a establecer en false
,
para evitar que ocurran operaciones de passkey no intencionadas más adelante en el código
de prueba.
Caso 2: Simulación de una entrada de passkey cancelada
Para una entrada de passkey cancelada, debemos hacer una ligera modificación a la
implementación del caso anterior. En el caso de una entrada de passkey exitosa, hay
eventos, a saber, WebAuthn.credentialAdded
y WebAuthn.credentialAsserted
, que se
emiten al finalizar la operación. Sin embargo, el autenticador virtual WebAuthn no
proporciona ningún evento para una entrada de passkey cancelada o fallida. Por lo tanto,
debemos usar una forma alternativa de verificar la finalización de una operación de
passkey cancelada o fallida.
Los siguientes fragmentos de código simulan una entrada de passkey fallida:
async simulateFailedPasskeyInput(operationTrigger: () => Promise<void>, postOperationCheck: () => Promise<void>) { // set isUserVerified option to false // (so that subsequent passkey operations will fail) await client.send('WebAuthn.setUserVerified', { authenticatorId: authenticatorId, isUserVerified: false, }); // set automaticPresenceSimulation option to true // (so that the virtual authenticator will respond to the next passkey prompt) await client.send('WebAuthn.setAutomaticPresenceSimulation', { authenticatorId: authenticatorId, enabled: true, }); // perform a user action that triggers passkey prompt await operationTrigger(); // wait for an expected UI change that indicates the passkey operation has completed await postOperationCheck(); // set automaticPresenceSimulation option back to false await client.send('WebAuthn.setAutomaticPresenceSimulation', { authenticatorId, enabled: false, }); }
test('signup with passkey', async ({ page }) => { // Simulate a set of user actions to trigger a passkey prompt ... await expect(page.getByRole('heading', { level: 1 })).toHaveText('Please log in'); // Simulate passkey input when prompted in the test await inputPasskey(async () => { await page.waitForTimeout(300); await expect(page.getByRole('heading', { level: 1 })).toHaveText('Please log in'); }); // Further test steps ... });
En la función de ayuda, los detectores de eventos se reemplazan con un parámetro de
promesa postOperationCheck
que espera que ocurra un cambio esperado en la interfaz de
usuario antes de que automaticPresenceSimulation
pueda volver a establecerse en false
.
En el código de prueba, la única diferencia es que la función de ayuda debe llamarse con
una promesa adicional que verifica el cambio de interfaz de usuario deseado. En el ejemplo
anterior, verificamos que la aplicación web haya navegado con éxito a una página en la que
el encabezado tiene el texto Something went wrong...
.
Como se discutió en la Sección 6.1.1, cancelar una entrada de passkey puede no conducir a ningún cambio observable en la interfaz de usuario. Al igual que en el ejemplo proporcionado en esa sección, debemos agregar una espera fija antes de verificar que la interfaz de usuario realmente ha permanecido igual en tales casos:
test('signup with passkey', async ({ page }) => { ... await expect(page.getByRole('heading', { level: 1 })).toHaveText('Please log in'); // Simulate passkey input with a promise that triggers a passkey prompt as the argument await simulateFailedPasskeyInput( () => page.getByRole('button', { name: 'Create account with passkeys' }).click(), async () => { await page.waitForTimeout(300); await expect(page.getByRole('heading', { level: 1 })).toHaveText('Please log in'); } ); ... });
La conveniencia de usar un autenticador virtual WebAuthn se ve reforzada por su capacidad para comportarse como un autenticador real en caso de creación o eliminación de passkeys por parte de la aplicación web. Una prueba simplemente necesita realizar acciones de usuario para simular la creación o eliminación de una passkey en la aplicación web, y el autenticador virtual WebAuthn modifica automáticamente la información de sus credenciales guardadas sin ningún trabajo adicional por parte del código de prueba.
Aquí está el ejemplo de código de prueba que verifica que la aplicación web registra una nueva passkey en el autenticador correctamente:
test('signup with passkey', async ({ page }) => { ... // Confirm there are currently no registered credentials const result1 = await client.send('WebAuthn.getCredentials', { authenticatorId }); expect(result1.credentials).toHaveLength(0); // Perform user actions to simulate creation of a passkey credential (e.g. user registration with passkey input) ... // Confirm the passkey was successfully registered const result2 = await client.send('WebAuthn.getCredentials', { authenticatorId }); expect(result2.credentials).toHaveLength(1); ... });
Combinando este fragmento de código con los fragmentos de código de la Sección 6.1, podemos probar el flujo de registro en nuestra página de demostración. El siguiente video es una visualización de la prueba en el modo de interfaz de usuario de Playwright:
Verificar una credencial de passkey con el autenticador virtual WebAuthn funciona de manera similar a la creación de una passkey, en el sentido de que el autenticador virtual realiza un seguimiento automático del número de verificaciones realizadas con una credencial en particular.
test('login with passkey', async ({ page }) => { ... // Confirm there is only one credential, and save its signCount const result1 = await client.send('WebAuthn.getCredentials', { authenticatorId }); expect(result1.credentials).toHaveLength(1); const signCount1 = result1.credentials[0].signCount; // Perform user actions to simulate verification of a passkey credential (e.g. login with passkey input) ... // Confirm the credential's new signCount is greater than the previous signCount const result2 = await client.send('WebAuthn.getCredentials', { authenticatorId }); expect(result2.credentials).toHaveLength(1); expect(result2.credentials[0].signCount).toBeGreaterThan(signCount1); ... });
El siguiente video demuestra una prueba para el flujo de inicio de sesión en nuestra página de demostración:
Eliminar una passkey de una aplicación web, por otro lado, no debería modificar ninguna información dentro del autenticador virtual WebAuthn. La aplicación web solo debería poder eliminar las credenciales guardadas en su propio servidor. Solo el propio usuario debería poder eliminar consciente y manualmente una credencial de passkey del autenticador virtual WebAuthn.
test('delete a registered passkey credential', async ({ page }) => { ... // Confirm there is currently one registered credential const result1 = await client.send('WebAuthn.getCredentials', { authenticatorId }); expect(result1.credentials).toHaveLength(1); // Perform user actions to simulate deletion of a passkey credential ... // Deleting a passkey credential from a website should not remove the credential from the authenticator const result2 = await client.send('WebAuthn.getCredentials', { authenticatorId }); expect(result2.credentials).toHaveLength(1); ... });
El siguiente video demuestra una prueba para la eliminación de una credencial de passkey en nuestra página de demostración:
La forma más intuitiva de simular una autenticación entre dispositivos desde un segundo dispositivo (que aún no tiene una passkey registrada) es simplemente agregar una nueva instancia del autenticador virtual WebAuthn a través del comando CDP, de la siguiente manera:
test('signup with passkey', async ({ page }) => { ... // add a virtual authenticator for the first device const authenticatorId1 = await client.send('WebAuthn.addVirtualAuthenticator', { options }); // perform test actions of the first device ... // add a virtual authenticator for the second device const authenticatorId2 = await client.send('WebAuthn.addVirtualAuthenticator', { options }); // perform test actions of the second device .. });
Para evitar la complejidad de gestionar los ID de múltiples autenticadores virtuales, también es posible simular un nuevo dispositivo simplemente eliminando las credenciales de un único autenticador y volviéndolas a agregar cuando sea necesario:
test('signup with passkey', async ({ page }) => { ... const result = await client.send('WebAuthn.getCredentials', { authenticatorId }); const credential = result.credentials[0]; // assuming only one registered passkey const credentialId = credential.credentialId; await client.send('WebAuthn.removeCredential', { authenticatorId, credentialId }); // Perform test actions of the second device which doesn't have a registered passkey ... // Call if it's necessary to simulate the first device which has a registered passkey await client.send('WebAuthn.addCredential', { credential }); // Perform test actions of the first device ... });
Este enfoque puede simplificar especialmente la implementación en el caso de que se necesite simular un nuevo dispositivo, pero el dispositivo antiguo ya no necesite ser utilizado. En este caso, simplemente necesitas borrar las credenciales del autenticador virtual y descartarlas por completo:
test('signup with passkey', async ({ page }) => { ... const result = await client.send('WebAuthn.getCredentials', { authenticatorId }); const credential = result.credentials[0]; // assuming only one registered passkey const credentialId = credential.credentialId; await client.send('WebAuthn.clearCredentials', { authenticatorId }); // Perform test actions of the second device which doesn't have a registered passkey ... });
Explorar alternativas al autenticador virtual WebAuthn puede ofrecer flexibilidad en la forma en que se prueban los procesos de autenticación de passkeys / WebAuthn dentro de los proyectos.
Desarrollar servicios o puntos finales simulados (mock) puede simular eficazmente el comportamiento de la autenticación, simplificando las pruebas al abstraer las complejidades del mecanismo de autenticación real. Este enfoque es particularmente beneficioso cuando se utilizan servicios de autenticación externos, permitiendo que el enfoque permanezca en la integración y funcionalidad de los componentes del sistema sin profundizar en los detalles de la autenticación.
Para un examen exhaustivo de las funcionalidades de autenticación, emplear autenticadores reales para las pruebas de integración proporciona una visión detallada de la interacción con llaves de seguridad de hardware (p. ej., YubiKeys) o dispositivos biométricos (p. ej., utilizados en Face ID, Touch ID o Windows Hello). Aunque generalmente se realiza de forma manual debido a la naturaleza compleja de integrar dispositivos del mundo real en pruebas automatizadas, es factible desarrollar scripts de automatización personalizados. Estos scripts pueden conectar autenticadores reales con marcos de pruebas de extremo a extremo, ofreciendo una aproximación más cercana a los escenarios de usuario reales y mejorando la fiabilidad del proceso de autenticación en entornos de producción.
Después de demostrar las diferentes opciones y mostrar fragmentos de código específicos para las pruebas E2E de passkeys / WebAuthn con Playwright, adicionalmente queremos proporcionar algunas recomendaciones más generales para los desarrolladores nuevos en el tema.
Antes de sumergirse en las pruebas de passkeys o cualquier otro mecanismo de autenticación, es esencial evaluar los marcos de pruebas E2E disponibles y elegir la opción más apropiada según los requisitos de tu proyecto. Considera el equilibrio entre la velocidad y la estabilidad que ofrecen los marcos basados en CDP como Playwright y Puppeteer, y la compatibilidad entre navegadores que proporcionan los marcos basados en WebDriver como Selenium y Nightwatch. Si bien los marcos basados en CDP ofrecen una automatización de navegadores más rápida y estable, están limitados a navegadores basados en Chromium. En contraste, los marcos basados en WebDriver proporcionan una compatibilidad entre navegadores más amplia, incluido el soporte para navegadores no basados en Chromium como Firefox y Safari, aunque con un rendimiento potencialmente más lento y menos estable. Comprender estas compensaciones te ayudará a tomar una decisión informada y a seleccionar el marco que mejor se adapte a las necesidades de tu proyecto.
Si bien el autenticador virtual WebAuthn simplifica el proceso de prueba de las implementaciones de passkeys, es crucial que los desarrolladores tengan una sólida comprensión de los conceptos subyacentes detrás del estándar WebAuthn y las passkeys. Familiarízate con las diferentes configuraciones disponibles para el autenticador virtual WebAuthn, como protocolo, transporte, hasResidentKey, hasUserVerification e isUserVerified. Comprender estas configuraciones te permitirá ajustar el autenticador virtual para simular diversos escenarios de autenticación con precisión. Además, profundiza en las complejidades de la autenticación con passkeys, incluida su integración con diferentes navegadores y dispositivos, así como las posibles consideraciones de seguridad. Este conocimiento fundamental te capacitará para diseñar estrategias de prueba completas y efectivas para la autenticación con passkeys en tus aplicaciones web.
Esta guía profundizó en el uso del autenticador virtual WebAuthn de CDP con Playwright, destacando conceptos avanzados y abordando problemas no cubiertos en la documentación oficial. También exploramos alternativas a CDP dentro de Playwright y otros marcos de pruebas E2E. A pesar de las diferentes implementaciones, las especificaciones estandarizadas del autenticador virtual WebAuthn aseguran la relevancia de esta guía en diferentes protocolos de automatización web y marcos de pruebas de extremo a extremo. Para aprender más en profundidad sobre diferentes conceptos relacionados con las passkeys, consulta nuestro glosario de terminologías relevantes que podrían ayudarte a ajustar el autenticador virtual WebAuthn según tus necesidades.
Enjoyed this read?
🤝 Join our Passkeys Community
Share passkeys implementation tips and get support to free the world from passwords.
🚀 Subscribe to Substack
Get the latest news, strategies, and insights about passkeys sent straight to your inbox.
Related Articles
Table of Contents