Impara a configurare i test E2E per le passkey su diversi browser con Playwright, Nightwatch, Selenium e Puppeteer utilizzando l'autenticatore virtuale WebAuthn.
Anders
Created: June 17, 2025
Updated: June 24, 2025
La nostra missione è rendere Internet un posto più sicuro, e il nuovo standard di login, le passkey, fornisce una soluzione superiore per raggiungere questo obiettivo. Ecco perché vogliamo aiutarti a comprendere meglio le passkey e le loro caratteristiche.
Le passkey stanno diventando sempre più accettate come metodo di autenticazione, basandosi su Web Authentication (WebAuthn) come standard sottostante. La loro crescente popolarità è piuttosto recente, il che rende la documentazione e altre risorse relativamente scarse. Questo, insieme alla natura complessa dell'implementazione delle passkey, può rendere difficile per gli sviluppatori trovare informazioni pertinenti sulla progettazione, l'implementazione e soprattutto il test delle passkey per le loro piattaforme e servizi.
Questa guida mira a colmare questa lacuna, concentrandosi sugli aspetti dell'autenticatore virtuale WebAuthn non trattati in modo approfondito nella sua documentazione ufficiale. Ad esempio, discutiamo le opzioni di configurazione per l'autenticatore virtuale che non sono autoesplicative nella documentazione, così come le soluzioni alternative per alcuni casi d'uso per i quali l'autenticatore virtuale non fornisce una soluzione comoda. Altrimenti, questa guida è utile anche per gli sviluppatori che cercano semplicemente esempi facili da seguire per utilizzare l'autenticatore virtuale nel codice di test.
La nostra guida utilizza esempi di Playwright per fornire una semplice procedura per testare efficacemente l'implementazione delle passkey nel tuo progetto. Playwright è un framework di test end-to-end (E2E) che utilizza il Chrome DevTools Protocol (CDP) come protocollo per l'automazione del browser. Se stai cercando specificamente esempi tecnici di test delle passkey in Playwright, puoi passare direttamente alla Sezione 5. D'altra parte, se stai utilizzando altri framework di test E2E come Puppeteer o Selenium e desideri testare le passkey su questi framework, le implementazioni del codice di test saranno identiche o molto simili agli esempi forniti in questa guida, a seconda del framework che stai utilizzando. Nella prossima sezione forniremo un background sui diversi framework di test E2E e su quanto questa guida sarà pertinente per questi framework.
Recent Articles
L'automazione del browser, come suggerisce il nome, è il processo di automatizzare azioni ripetitive dell'utente sul browser allo scopo di estrarre dati dal web o, nel nostro caso, di testare applicazioni web. WebDriver e Chrome DevTools Protocol (CDP) sono due dei principali protocolli di automazione del browser rilevanti per questa guida, poiché entrambi forniscono un'implementazione dell'autenticatore virtuale WebAuthn.
WebDriver è un'interfaccia controllata a distanza che può essere vista come un intermediario nella comunicazione tra il client e il browser. L'obiettivo di questo protocollo è fornire un'interfaccia neutrale rispetto alla piattaforma e al linguaggio che supporti tutti i principali browser, inclusi quelli non basati su Chromium come Firefox e Safari. Poiché l'interfaccia WebDriver deve gestire una connessione sia con il client che con il browser, questo approccio sacrifica velocità e stabilità in cambio di un più ampio supporto di browser (cioè una maggiore instabilità o 'flakiness'). Client WebDriver notevoli includono Selenium e Nightwatch.
Tratto da jankaritech
Il Chrome DevTools Protocol (CDP), d'altra parte, non ha un intermediario come l'interfaccia WebDriver tra il client e il browser. Inoltre, la comunicazione tra il client e il browser avviene tramite una connessione socket, in contrasto con la più lenta connessione HTTP tra il client e l'interfaccia WebDriver nell'approccio precedente. Questi punti rendono il CDP molto più veloce e meno instabile ('flaky') di WebDriver. Lo svantaggio è che questo protocollo è supportato solo per i browser basati su Chromium come Chrome ed Edge. Playwright e Puppeteer sono esempi di client che utilizzano il CDP per comunicare con i browser.
Tratto da jankaritech
Puppeteer, simile a Playwright, è un framework E2E costruito direttamente sul CDP. Ciò significa che Puppeteer e Playwright utilizzano entrambi la stessa implementazione dell'autenticatore virtuale WebAuthn e che anche la comunicazione API tramite l'autenticatore virtuale WebAuthn via connessione socket è identica.
Per dimostrare, confrontiamo il codice di test sia in Playwright che in Puppeteer per chiamare il metodo getCredentials che restituisce un elenco di tutte le credenziali registrate finora nell'autenticatore virtuale. Alleghiamo anche un semplice listener di eventi per l'evento credentialAdded che viene attivato quando una credenziale passkey viene registrata con successo. Non lasciarti intimidire dai dettagli dell'implementazione, poiché saranno spiegati nelle sezioni successive. Questi esempi servono semplicemente a dimostrare quanto siano simili le implementazioni tra i due framework.
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.
Oltre 10.000 sviluppatori si fidano di Corbado e rendono Internet più sicuro con le passkey. Hai domande? Abbiamo scritto più di 150 articoli del blog sulle passkey.
Unisciti alla community delle passkeyPlaywright:
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!'); });
Sebbene i metodi per inizializzare la sessione CDP all'inizio dei codici di test fossero leggermente diversi, la chiamata dei metodi e la gestione degli eventi nell'API dell'autenticatore virtuale WebAuthn del CDP è identica. Ciò significa che se stai cercando di utilizzare l'autenticatore virtuale WebAuthn in Puppeteer, puoi seguire questa guida riga per riga.
Selenium e Nightwatch sono framework di test E2E che si basano su WebDriver per l'automazione del browser. Sebbene l'implementazione dell'autenticatore virtuale WebAuthn per WebDriver sia separata dalla sua implementazione per CDP, le loro specifiche API sono simili. Per quasi ogni metodo nell'API dell'autenticatore virtuale WebAuthn del CDP, puoi trovare un metodo corrispondente nell'API dell'autenticatore virtuale WebAuthn di WebDriver. Tuttavia, una cosa da notare è che mentre era possibile associare listener di eventi per quando una passkey viene aggiunta o asserita con successo nell'API dell'autenticatore virtuale WebAuthn del CDP, questo non è possibile nella controparte 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();
È evidente che la sintassi per configurare l'istanza dell'autenticatore virtuale e fare chiamate API è diversa dalla corrispondente implementazione CDP. Tuttavia, poiché le specifiche API dei due autenticatori virtuali WebAuthn sono molto simili, sarebbe fattibile seguire questa guida per scrivere un'implementazione corrispondente su un framework di test E2E basato su WebDriver.
Cypress è un framework di test E2E che non è costruito principalmente su WebDriver o CDP come i framework menzionati sopra. Utilizza JavaScript nativo per comunicare con il browser. Tuttavia, fornisce un accesso a basso livello al CDP, il che significa che è possibile inviare comandi CDP grezzi per utilizzare l'autenticatore virtuale WebAuthn del CDP.
Poiché la sintassi per questo accesso a basso livello è noiosa e molto diversa dagli esempi precedenti, non entreremo nei dettagli in questa guida. Tuttavia, ulteriori informazioni su come chiamare i comandi CDP in Cypress sono spiegate in questa guida. I concetti generali per l'utilizzo dell'autenticatore virtuale WebAuthn del CDP presentati in questa guida sono ancora pertinenti per coloro che cercano di testare le passkey su Cypress.
Ci sono molte ragioni per cui testare l'implementazione delle passkey è naturalmente più impegnativo rispetto ad altre azioni utente più semplici in un ambiente web. La necessità di gestire interazioni utente dinamiche coinvolte con l'autenticazione biometrica, come la scansione delle impronte digitali o il riconoscimento facciale, aggiunge uno strato di complessità che potrebbe non essere pratico affrontare in dettaglio durante la scrittura dei test. Poiché la sicurezza è naturalmente una preoccupazione principale nel contesto dell'autenticazione, è anche necessario garantire che l'autenticazione con passkey sia integrata senza problemi su vari browser e dispositivi, senza lasciare spazio a vulnerabilità di sicurezza.
Semplificare la complessità della gestione delle interazioni utente dinamiche coinvolte nelle operazioni con le passkey, così come testare la loro integrazione in diversi browser e dispositivi, è reso più facile utilizzando l'autenticatore virtuale WebAuthn.
L'autenticatore virtuale WebAuthn è una rappresentazione software del modello di autenticatore specificato nello standard WebAuthn. Emula il comportamento di un dispositivo autenticatore fisico, come una chiave di sicurezza hardware (ad es. YubiKey) o uno scanner biometrico (ad es. utilizzato in Face ID, Touch ID o Windows Hello), ma opera interamente via software (quindi non è coinvolta alcuna autenticazione fisica o scansione biometrica).
Ci sono due vantaggi principali per l'autenticatore virtuale WebAuthn.
Poiché WebDriver e CDP sono strumenti di automazione del browser, è evidente che il caso d'uso primario dell'implementazione dell'autenticatore virtuale WebAuthn in questi protocolli è il test automatizzato. Sfruttando questi protocolli, l'autenticatore virtuale consente test semplici ma completi delle funzionalità delle passkey in ambienti controllati come i framework di test E2E (ad es. Playwright, Cypress, Nightwatch).
L'autenticatore virtuale WebAuthn del CDP è accessibile anche tramite i DevTools del browser Chrome e può essere utilizzato per test manuali o semplicemente a scopo dimostrativo. Con questa funzione è possibile simulare l'input di una passkey su un dispositivo che non supporta nativamente le passkey. Di conseguenza, è anche possibile simulare un ambiente non supportato dalle passkey su un dispositivo che le supporta.
Lo screenshot qui sopra mostra un esempio di utilizzo dell'autenticatore virtuale in Chrome per test manuali o a scopo dimostrativo. Si può vedere che sono possibili diverse opzioni di configurazione per l'autenticatore virtuale, e si può anche tracciare l'aggiunta e la cancellazione delle credenziali. Fai riferimento a questa guida di Google per maggiori informazioni sull'utilizzo dell'autenticatore virtuale nel tuo browser, incluse le opzioni di configurazione e i valori raccomandati per ciascuna.
Sebbene l'autenticatore virtuale WebAuthn sia una soluzione elegante per testare le implementazioni delle passkey, ci sono alcuni svantaggi da notare.
Essendo una soluzione puramente basata su software, l'autenticatore virtuale WebAuthn non può replicare le caratteristiche hardware uniche e le funzionalità di sicurezza degli autenticatori fisici. La distinzione tra l'uso di vari autenticatori di piattaforma (che sono integrati in un dispositivo, come uno scanner biometrico su uno smartphone) e vari autenticatori multipiattaforma (che sono dispositivi esterni, come le chiavi di sicurezza hardware) non può essere simulata utilizzando l'autenticatore virtuale WebAuthn. Sebbene la semplificazione black-box delle complessità legate ai vari tipi di autenticatori di piattaforma e multipiattaforma sia uno dei vantaggi dell'utilizzo dell'autenticatore virtuale WebAuthn, se si cerca di simulare e testare le sfumature dei diversi tipi di autenticatori, si dovrebbero esplorare altre soluzioni.
Data l'adozione relativamente recente di WebAuthn e la novità della tecnologia delle passkey, l'ecosistema che circonda gli autenticatori virtuali è ancora in fase di maturazione. Ciò si traduce in una scarsità di documentazione completa e in sfide tecniche irrisolte, in particolare nel contesto dell'integrazione degli autenticatori virtuali con i framework di test automatizzati. Questa guida mira ad affrontare questo problema fornendo approfondimenti completi sul test delle passkey in un ambiente di test automatizzato, concentrandosi anche sulla risoluzione degli inconvenienti ancora presenti nell'uso di questi strumenti e presentando soluzioni alternative per questi problemi.
Dopo un'installazione riuscita di Playwright e delle sue dipendenze, puoi iniziare subito a scrivere il tuo primo test creando un file con un nome che termina in .spec.ts o .test.ts con il seguente contenuto:
import { test, expect } from "@playwright/test"; test("my first test", async ({ page }) => { await page.goto("https://passkeys.eu"); // start simulating user actions });
Per utilizzare l'autenticatore virtuale WebAuthn in Playwright, è sufficiente avviare una sessione CDP e collegare un autenticatore virtuale all'inizio di un caso di test, come segue:
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 ... });
Opzioni per la configurazione dell'autenticatore virtuale WebAuthn:
In questa sezione, esploriamo l'uso dei metodi e degli eventi dell'autenticatore virtuale WebAuthn nel contesto di casi d'uso sia comuni che marginali.
Questo potrebbe essere il compito più importante ma anche più confusionario quando si utilizza l'autenticatore virtuale WebAuthn in un codice di test, poiché non esiste un metodo integrato esplicito per attivare un input di passkey. La soluzione risiede nelle opzioni di configurazione dell'autenticatore virtuale WebAuthn, ovvero, isUserVerified e automaticPresenceSimulation. Con queste opzioni possiamo simulare questa interazione dell'utente tramite due approcci diversi descritti di seguito.
Caso 1: Simulare un input di passkey riuscito
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!'); ... });
La simulazione di un input di passkey riuscito di solito non richiede righe aggiuntive nel codice di test. La riga finale (await expect...) attende che la pagina cambi (attivata dall'input di passkey riuscito implicito).
Caso 2: Simulare un input di passkey annullato (che non provoca modifiche nell'interfaccia utente)
Testare un input di passkey fallito o annullato è più complicato poiché potrebbe non portare a cambiamenti osservabili nell'interfaccia utente. In altre parole, attendere che la pagina cambi come nell'esempio precedente non è adeguato per garantire che l'input della passkey abbia completato l'elaborazione. Controllare che la pagina non sia cambiata dopo l'input implicito della passkey non ha senso, poiché il controllo avverrà quasi certamente prima che l'input della passkey abbia completato l'elaborazione. Sebbene l'autenticatore virtuale fornisca un modo per attendere che un input di passkey riuscito venga elaborato ascoltando l'emissione di eventi (come verrà discusso nell'approccio 2), attualmente non esiste un modo integrato per rilevare un input di passkey fallito o annullato. Una soluzione alternativa sarebbe semplicemente aggiungere un timeout fisso per attendere che l'operazione della passkey si completi prima di verificare che l'interfaccia utente sia effettivamente rimasta la stessa.
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 ... });
In entrambi i casi, la leggibilità del codice di test è limitata dall'implicità dell'operazione della passkey. Come menzionato in precedenza, sarebbe anche facile trascurare quando potrebbe essere richiesta una Conditional UI, nel qual caso l'operazione della passkey si completerebbe automaticamente senza che il tester ne sia a conoscenza.
Attivare manualmente un input di passkey cambiando il valore dell'opzione automaticPresenceSimulation risolve i problemi riscontrati nell'approccio precedente, in particolare in termini di leggibilità del codice di test.
Caso 1: Simulare un input di passkey riuscito
I seguenti frammenti di codice simulano un input di passkey riuscito:
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 funzione di supporto potrebbe essere piuttosto intimidatoria a prima vista. È utile capire che tutte le complessità tecniche della simulazione di un'operazione con passkey sono astratte nella funzione di supporto. Ciò significa che quando viene utilizzata all'interno del codice di test, rende il codice semplice e chiaro, come si può vedere nel secondo frammento di codice sopra.
Rispetto all'approccio implicito nella Sezione 6.1.1, questo approccio esplicito aumenta anche la leggibilità del codice. Ciò sarebbe particolarmente utile quando viene richiesta una Conditional UI, poiché questo approccio esplicito previene il completamento involontario e implicito dell'operazione con passkey senza che lo sviluppatore se ne accorga.
Ora analizziamo ogni parte della funzione di supporto.
Innanzitutto, definiamo la promise operationCompleted che attende l'evento WebAuthn.credentialAdded o l'evento WebAuthn.credentialAsserted, che, come suggerisce il nome, viene emesso quando una credenziale passkey viene registrata o verificata, rispettivamente. Questa promise verrà utilizzata in seguito.
Successivamente, l'opzione isUserVerified viene impostata su true, in modo che la successiva operazione con passkey da parte dell'autenticatore virtuale WebAuthn abbia successo. Anche automaticPresenceSimulation viene impostato su true, in modo che l'autenticatore virtuale WebAuthn risponda alla successiva richiesta di passkey dalla pagina web.
L'attesa della promise operationTrigger è necessaria per evitare una race condition. La race condition si verifica quando la pagina web richiede la passkey prima che automaticPresenceSimulation sia impostato su true. Per evitare ciò, l'azione dell'utente che attiva la richiesta di passkey deve essere eseguita dopo che automaticPresenceSimulation è stato impostato su true. Nell'esempio sopra, l'utente fa clic sul pulsante denominato Create account with passkeys per attivare la richiesta di passkey.
Dopo che l'azione dell'utente è stata completata, dobbiamo attendere il completamento dell'operazione di passkey riuscita. Questo viene fatto attendendo la promise che abbiamo definito all'inizio della funzione di supporto. Il completamento dell'operazione di passkey riuscita è contrassegnato dall'emissione dell'evento WebAuthn.credentialAdded o WebAuthn.credentialAsserted. Nell'esempio sopra, poiché l'utente sta registrando una passkey, verrebbe emesso l'evento WebAuthn.credentialAdded.
Infine, l'opzione automaticPresenceSimulation viene reimpostata su false, per evitare che operazioni di passkey involontarie si verifichino più tardi nel codice di test.
Caso 2: Simulare un input di passkey annullato
Per un input di passkey annullato, dobbiamo apportare una leggera modifica all'implementazione del caso precedente. Nel caso di un input di passkey riuscito, ci sono eventi, ovvero WebAuthn.credentialAdded e WebAuthn.credentialAsserted, che vengono emessi al completamento dell'operazione. Tuttavia, l'autenticatore virtuale WebAuthn non fornisce alcun evento per un input di passkey annullato o fallito. Pertanto, dobbiamo utilizzare un modo alternativo per verificare il completamento di un'operazione di passkey annullata o fallita.
I seguenti frammenti di codice simulano un input di passkey fallito:
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 ... });
Nella funzione di supporto, i listener di eventi sono sostituiti da un parametro promise postOperationCheck che attende che si verifichi una modifica prevista dell'interfaccia utente prima che automaticPresenceSimulation possa essere reimpostato su false.
Nel codice di test, l'unica differenza è che la funzione di supporto deve essere chiamata con una promise aggiuntiva che controlla la modifica prevista dell'interfaccia utente. Nell'esempio sopra, controlliamo che l'applicazione web sia navigata con successo a una pagina in cui l'intestazione ha il testo Something went wrong....
Come discusso nella Sezione 6.1.1, l'annullamento di un input di passkey potrebbe non portare a cambiamenti osservabili nell'interfaccia utente. Come nell'esempio fornito in quella sezione, dobbiamo aggiungere un'attesa fissa prima di verificare che l'interfaccia utente sia effettivamente rimasta la stessa in tali casi:
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 comodità di utilizzare un autenticatore virtuale WebAuthn è accresciuta dalla sua capacità di comportarsi come un vero autenticatore in caso di creazione o cancellazione di passkey da parte dell'applicazione web. Un test deve semplicemente eseguire azioni utente per simulare la creazione o la cancellazione di una passkey sull'applicazione web, e l'autenticatore virtuale WebAuthn modifica automaticamente le informazioni sulle credenziali salvate senza alcun lavoro aggiuntivo da parte del codice di test.
Ecco l'esempio di codice di test che verifica che l'applicazione web registri correttamente una nuova passkey nell'autenticatore:
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 questo frammento di codice con quelli della Sezione 6.1, possiamo testare il flusso di registrazione sulla nostra pagina web demo. Il seguente video è una visualizzazione del test in modalità UI di Playwright:
La verifica di una credenziale passkey con l'autenticatore virtuale WebAuthn funziona in modo simile alla creazione di una passkey, in quanto l'autenticatore virtuale tiene traccia automaticamente del numero di verifiche eseguite utilizzando una particolare credenziale.
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); ... });
Il seguente video dimostra un test per il flusso di login sulla nostra pagina web demo:
La cancellazione di una passkey da un'applicazione web, d'altra parte, non dovrebbe modificare alcuna informazione all'interno dell'autenticatore virtuale WebAuthn. L'applicazione web dovrebbe essere in grado di cancellare solo le credenziali salvate nel proprio server. Solo l'utente stesso dovrebbe essere in grado di cancellare consapevolmente e manualmente una credenziale passkey dall'autenticatore virtuale 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); ... });
Il seguente video dimostra un test per la cancellazione di una credenziale passkey sulla nostra pagina web demo:
Il modo più intuitivo per simulare un'autenticazione tra dispositivi diversi da un secondo dispositivo (che non ha ancora una passkey registrata) è semplicemente aggiungere una nuova istanza dell'autenticatore virtuale WebAuthn tramite il comando CDP, in questo modo:
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 .. });
Per evitare la complessità di gestire gli ID di più autenticatori virtuali, è anche possibile simulare un nuovo dispositivo semplicemente cancellando le credenziali da un singolo autenticatore e aggiungendole di nuovo quando necessario:
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 ... });
Questo approccio può semplificare particolarmente l'implementazione nel caso in cui sia necessario simulare un nuovo dispositivo, ma il vecchio dispositivo non debba più essere utilizzato. In questo caso, è sufficiente cancellare le credenziali dall'autenticatore virtuale e scartarle del tutto:
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 ... });
Esplorare alternative all'autenticatore virtuale WebAuthn può offrire flessibilità nel modo in cui i processi di autenticazione passkey / WebAuthn vengono testati all'interno dei progetti.
Lo sviluppo di servizi o endpoint mock può simulare efficacemente il comportamento di autenticazione, semplificando i test astraendo le complessità del meccanismo di autenticazione effettivo. Questo approccio è particolarmente vantaggioso quando si utilizzano servizi di autenticazione esterni, consentendo di mantenere il focus sull'integrazione e la funzionalità dei componenti del sistema senza approfondire le specifiche dell'autenticazione.
Per un esame approfondito delle funzionalità di autenticazione, l'impiego di autenticatori reali per i test di integrazione fornisce una visione dettagliata dell'interazione con le chiavi di sicurezza hardware (ad es. YubiKeys) o i dispositivi biometrici (ad es. utilizzati in Face ID, Touch ID o Windows Hello). Sebbene tipicamente condotto manualmente a causa della natura complessa dell'integrazione di dispositivi reali nei test automatizzati, è fattibile sviluppare script di automazione personalizzati. Questi script possono collegare autenticatori reali con framework di test end-to-end, offrendo un'approssimazione più vicina agli scenari utente reali e migliorando l'affidabilità del processo di autenticazione in ambienti live.
Dopo aver dimostrato le diverse opzioni e mostrato frammenti di codice specifici per il test E2E di passkey / WebAuthn con Playwright, vogliamo inoltre fornire alcune raccomandazioni più generali per gli sviluppatori che si avvicinano a questo argomento.
Prima di immergersi nel test delle passkey o di qualsiasi altro meccanismo di autenticazione, è essenziale valutare i framework di test E2E disponibili e scegliere l'opzione più appropriata in base ai requisiti del proprio progetto. Considera il compromesso tra la velocità e la stabilità offerte dai framework basati su CDP come Playwright e Puppeteer, e la compatibilità cross-browser fornita dai framework basati su WebDriver come Selenium e Nightwatch. Mentre i framework basati su CDP offrono un'automazione del browser più veloce e stabile, sono limitati ai browser basati su Chromium. Al contrario, i framework basati su WebDriver forniscono una più ampia compatibilità cross-browser, incluso il supporto per browser non-Chromium come Firefox e Safari, sebbene con prestazioni potenzialmente più lente e meno stabili. Comprendere questi compromessi ti aiuterà a prendere una decisione informata e a selezionare il framework che meglio si adatta alle esigenze del tuo progetto.
Sebbene l'autenticatore virtuale WebAuthn semplifichi il processo di test delle implementazioni delle passkey, è fondamentale che gli sviluppatori abbiano una solida comprensione dei concetti alla base dello standard WebAuthn e delle passkey. Familiarizza con le diverse configurazioni disponibili per l'autenticatore virtuale WebAuthn, come protocol, transport, hasResidentKey, hasUserVerification e isUserVerified. Comprendere queste configurazioni ti consentirà di affinare l'autenticatore virtuale per simulare accuratamente vari scenari di autenticazione. Inoltre, approfondisci le complessità dell'autenticazione con passkey, inclusa la sua integrazione con diversi browser e dispositivi, nonché le potenziali considerazioni sulla sicurezza. Questa conoscenza fondamentale ti darà il potere di progettare strategie di test complete ed efficaci per l'autenticazione con passkey nelle tue applicazioni web.
Questa guida ha approfondito l'uso dell'autenticatore virtuale WebAuthn del CDP con Playwright, evidenziando concetti avanzati e affrontando problemi non trattati nella documentazione ufficiale. Abbiamo anche esplorato alternative al CDP all'interno di Playwright e altri framework di test E2E. Nonostante le diverse implementazioni, le specifiche standardizzate dell'autenticatore virtuale WebAuthn garantiscono la pertinenza di questa guida per diversi protocolli di automazione web e framework di test end-to-end. Per approfondire i diversi concetti relativi alle passkey, fai riferimento al nostro glossario di terminologie pertinenti che potrebbe aiutarti a perfezionare l'autenticatore virtuale WebAuthn in base alle tue esigenze.
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