WebAuthn仮想認証器を使い、Playwright、Nightwatch、Selenium、PuppeteerでブラウザをまたいだパスキーのE2Eテストを設定する方法を解説します。
Anders
Created: June 17, 2025
Updated: June 20, 2025
「私たちの使命は、インターネットをより安全な場所にすることです」。そして、新しいログイン標準であるパスキーは、それを達成するための優れたソリューションを提供します。そのため、私たちは皆様がパスキーとその特性をより深く理解できるよう支援したいと考えています。
パスキーは、その基盤となる標準としてWeb Authentication(WebAuthn)に依存し、認証方法としてますます広く受け入れられるようになっています。その人気の高まりはごく最近のことであるため、ドキュメントやその他のリソースは比較的乏しいのが現状です。これは、パスキー実装の複雑な性質と相まって、開発者が自身のプラットフォームやサービス向けにパスキーを設計、実装、そして特にテストするための関連情報を見つけることを困難にする可能性があります。
このガイドは、そのギャップを埋めることを目的としており、その公式ドキュメントで十分にカバーされていないWebAuthn仮想認証器の側面に焦点を当てています。例えば、ドキュメントでは自明ではない仮想認証器の設定オプションや、仮想認証器が便利な解決策を提供していない特定のユースケースに対する回避策について説明します。また、このガイドは、テストコードで仮想認証器を使用するための分かりやすい例を探している開発者にとっても役立ちます。
このガイドでは、Playwrightの例を使用して、プロジェクトでパスキー実装を効果的にテストするための簡単なウォークスルーを提供します。Playwrightは、ブラウザ自動化のプロトコルとしてChrome DevTools Protocol(CDP)を使用するエンドツーエンド(E2E)テストフレームワークです。特にPlaywrightでパスキーをテストする技術的な例をお探しの場合は、セクション5に進んでください。一方、PuppeteerやSeleniumのような他のE2Eテストフレームワークを使用していて、これらのフレームワークでパスキーをテストしたい場合、テストコードの実装は、使用しているフレームワークに応じて、このガイドで提供される例と同一または非常に類似したものになります。次のセクションでは、さまざまなE2Eフレームワークの背景と、このガイドがこれらのフレームワークにどれほど関連性があるかについて説明します。
ブラウザ自動化とは、その名の通り、ウェブからデータを収集したり、今回のケースのようにウェブアプリケーションをテストしたりする目的で、ブラウザ上の反復的なユーザーアクションを自動化するプロセスです。WebDriverとChrome DevTools Protocol(CDP)は、このガイドに関連する2つの主要なブラウザ自動化プロトコルであり、それぞれがWebAuthn仮想認証器の実装を提供しています。
WebDriverは、クライアントとブラウザ間の通信における仲介役と見なすことができるリモート制御インターフェースです。このプロトコルの焦点は、FirefoxやSafariなどChromiumベースでないものを含む、すべての主要なブラウザをサポートするプラットフォームおよび言語に中立なインターフェースを提供することです。WebDriverインターフェースはクライアントとブラウザの両方との接続を管理する必要があるため、このアプローチは、より広範なブラウザサポートと引き換えに速度と安定性を犠牲にします(つまり、テストの不安定性が高くなります)。著名なWebDriverクライアントには、SeleniumやNightwatchがあります。
jankaritechより引用
一方、Chrome DevTools Protocol(CDP)には、WebDriverインターフェースのようなクライアントとブラウザ間の仲介役が存在しません。さらに、クライアントとブラウザ間の通信はソケット接続を介して行われますが、これは前のアプローチにおけるクライアントとWebDriverインターフェース間の低速なHTTP接続とは対照的です。これらの点により、CDPはWebDriverよりもはるかに高速で安定しています。欠点は、このプロトコルがChromeやEdgeなどのChromiumベースのブラウザでのみサポートされていることです。PlaywrightとPuppeteerは、CDPを使用してブラウザと通信するクライアントの例です。
jankaritechより引用
Puppeteerは、Playwrightと同様に、CDP上に直接構築されたE2Eフレームワークです。これは、PuppeteerとPlaywrightがどちらも同じWebAuthn仮想認証器の実装を使用し、ソケット接続を介したWebAuthn仮想認証器を使用したAPI通信も同一であることを意味します。
これを実証するために、PlaywrightとPuppeteerの両方で、これまでに仮想認証器に登録されたすべての資格情報のリストを返すgetCredentialsメソッドを呼び出すテストコードを比較します。また、パスキー資格情報が正常に登録されたときにトリガーされるcredentialAddedイベントの簡単なイベントリスナーもアタッチします。実装の詳細に気後れする必要はありません。これらは後のセクションで説明します。これらの例は、2つのフレームワーク間で実装がどれほど類似しているかを示すためのものです。
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.
10,000+ devs trust Corbado & make the Internet safer with passkeys. Got questions? We've written 150+ blog posts on passkeys.
Join Passkeys CommunityPlaywright:
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!'); });
テストコードの冒頭でCDPセッションを初期化する方法はわずかに異なりますが、CDP WebAuthn仮想認証器APIでのメソッド呼び出しやイベント処理は同一です。これは、PuppeteerでWebAuthn仮想認証器を使用したい場合、このガイドを一行ずつ追うことができることを意味します。
SeleniumとNightwatchは、ブラウザ自動化にWebDriverを利用するE2Eテストフレームワークです。WebDriver用のWebAuthn仮想認証器の実装はCDP用の実装とは別ですが、API仕様は似ています。CDP WebAuthn仮想認証器APIのほぼすべてのメソッドに対して、WebDriver WebAuthn仮想認証器APIに対応するメソッドを見つけることができます。ただし、注意すべき点の1つは、CDP WebAuthn仮想認証器APIではパスキーが正常に追加またはアサートされたときにイベントリスナーをアタッチできましたが、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();
仮想認証器インスタンスのセットアップやAPI呼び出しの構文が、対応するCDP実装とは異なることは明らかです。しかし、2つのWebAuthn仮想認証器のAPI仕様は非常に似ているため、このガイドに従ってWebDriverベースのE2Eテストフレームワーク上で対応する実装を作成することは可能です。
Cypressは、上記のフレームワークのように主にWebDriverやCDP上に構築されているわけではないE2Eテストフレームワークです。ブラウザとの通信にはネイティブのJavaScriptを使用します。しかし、CDPへの低レベルアクセスを提供しており、これにより生のCDPコマンドを送信してCDPのWebAuthn仮想認証器を利用することが可能です。
この低レベルアクセスの構文は退屈で、上記の例とは大きく異なるため、このガイドでは詳細には触れません。しかし、CypressでCDPコマンドを呼び出す方法に関する詳細な情報は、このガイドで説明されています。このガイドで提示されているCDP WebAuthn仮想認証器を使用するための全体像の概念は、Cypressでパスキーをテストしようとしている人々にとって依然として関連性があります。
ウェブ環境における他のより単純なユーザーアクションと比較して、パスキー実装のテストが本質的により困難である理由はたくさんあります。指紋スキャンや顔認証などの生体認証に伴う動的なユーザーインタラクションを処理する必要性は、テストを作成する際に詳細に対処することが現実的ではないかもしれない複雑さの層を追加します。認証の文脈ではセキュリティが当然ながら大きな懸念事項であるため、パスキー認証がセキュリティの脆弱性の余地なく、さまざまなブラウザやデバイス間でシームレスに統合されていることを保証することも必要です。
パスキー操作に伴う動的なユーザーインタラクションの処理の複雑さを単純化し、さまざまなブラウザやデバイスへの統合をテストすることは、WebAuthn仮想認証器を使用することで容易になります。
WebAuthn仮想認証器は、WebAuthn標準で指定された認証器モデルのソフトウェア表現です。ハードウェアセキュリティキー(例:YubiKey)や生体認証スキャナー(例:Face ID、Touch ID、Windows Helloで使用)などの物理的な認証器デバイスの動作をエミュレートしますが、完全にソフトウェア内で動作します(したがって、物理的な認証や生体情報のスキャンは伴いません)。
WebAuthn仮想認証器には主に2つの利点があります。
WebDriverとCDPはブラウザ自動化ツールであるため、これらのプロトコルにおけるWebAuthn仮想認証器実装の主なユースケースが自動テストであることは明らかです。これらのプロトコルを活用することで、仮想認証器は、E2Eテストフレームワーク(例:Playwright、Cypress、Nightwatch)などの制御された環境で、パスキー機能のシンプルかつ包括的なテストを可能にします。
CDPのWebAuthn仮想認証器は、ChromeブラウザのDevToolsからもアクセスでき、手動テストや単なるデモンストレーション目的で使用できます。この機能を使用すると、ネイティブでパスキーをサポートしていないデバイスでパスキー入力をシミュレートできます。同様に、パスキーをサポートするデバイスでパスキー非対応の環境をシミュレートすることも可能です。
上のスクリーンショットは、手動テストやデモンストレーション目的でChromeの仮想認証器を使用する例を示しています。仮想認証器にはさまざまな設定オプションが可能であり、資格情報の追加や削除も追跡できることがわかります。ブラウザで仮想認証器を使用する方法(設定オプションやそれぞれの推奨値を含む)の詳細については、Googleのこのガイドを参照してください。
WebAuthn仮想認証器はパスキー実装をテストするためのエレガントなソリューションですが、注意すべきいくつかの欠点があります。
純粋にソフトウェアベースのソリューションであるため、WebAuthn仮想認証器は、物理的な認証器の独自のハードウェア特性やセキュリティ機能を再現することはできません。さまざまなプラットフォーム認証器(スマートフォンの生体認証スキャナーなど、デバイスに組み込まれているもの)とさまざまなクロスプラットフォーム認証器(ハードウェアセキュリティキーのような外部デバイス)の使用の違いは、WebAuthn仮想認証器を使用してシミュレートすることはできません。さまざまな種類のプラットフォーム認証器やクロスプラットフォーム認証器に伴う複雑さをブラックボックス化して単純化することは、WebAuthn仮想認証器を使用する利点の1つですが、さまざまな種類の認証器のニュアンスをシミュレートしてテストしたい場合は、他のソリューションを検討する必要があります。
WebAuthnの比較的新しい採用とパスキー技術の新規性を考えると、仮想認証器を取り巻くエコシステムはまだ成熟段階にあります。これにより、特に自動テストフレームワークと仮想認証器を統合する文脈で、包括的なドキュメントの不足や未解決の技術的課題が生じています。このガイドは、自動テスト環境でパスキーをテストするための包括的な洞察を提供すると同時に、これらのツールの使用に依然として存在する不便さに対処し、これらの問題に対する回避策を提示することで、この問題に対処することを目指しています。
Playwrightとその依存関係のインストールが成功した後、.spec.tsまたは.test.tsで終わる名前のファイルに次の内容を記述することで、すぐに最初のテストを書き始めることができます。
import { test, expect } from "@playwright/test"; test("my first test", async ({ page }) => { await page.goto("https://passkeys.eu"); // start simulating user actions });
PlaywrightでWebAuthn仮想認証器を使用するには、テストケースの冒頭でCDPセッションを開始し、仮想認証器をアタッチするだけで十分です。
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 ... });
WebAuthn仮想認証器を設定するためのオプション:
このセクションでは、一般的および特殊なユースケースの両方の文脈で、WebAuthn仮想認証器のメソッドとイベントの使用法を探ります。
これは、テストコードでWebAuthn仮想認証器を使用する際に最も重要でありながら混乱を招く可能性のあるタスクかもしれません。なぜなら、パスキー入力をトリガーするための明示的な組み込みメソッドがないからです。解決策は、WebAuthn仮想認証器の設定オプション、すなわちisUserVerifiedとautomaticPresenceSimulationにあります。これらのオプションを使用して、以下に説明する2つの異なるアプローチを介してこのユーザーインタラクションをシミュレートできます。
ケース1:成功したパスキー入力のシミュレーション
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!'); ... });
成功したパスキー入力をシミュレートするには、通常、テストコードに追加の行は必要ありません。最後の行(await expect...)は、暗黙的な成功したパスキー入力によってトリガーされるページの変更を待ちます。
ケース2:キャンセルされたパスキー入力のシミュレーション(UIの変更をトリガーしない)
失敗した、またはキャンセルされたパスキー入力のテストは、UIに観察可能な変更をもたらさない可能性があるため、より複雑です。言い換えれば、前の例のようにページの変更を待つだけでは、パスキー入力の処理が完了したことを保証するには不十分です。暗黙的なパスキー入力後にページが変わっていないことを確認することは無意味です。なぜなら、そのチェックはパスキー入力の処理が完了する前にほぼ確実に行われるからです。仮想認証器は、イベント発行をリッスンすることで成功したパスキー入力が処理されるのを待つ方法を提供しますが(アプローチ2で説明します)、現在、失敗した、またはキャンセルされたパスキー入力を検出する組み込みの方法はありません。回避策は、単純に固定のタイムアウトを追加してパスキー操作が完了するのを待ってから、UIが実際に同じままであることを確認することです。
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 ... });
どちらの場合も、テストコードの可読性はパスキー操作の暗黙性によって制限されます。前述のように、条件付きUIがいつプロンプトされるかを見落としやすく、その場合、パスキー操作はテスターの知らないうちに自動的に完了してしまいます。
automaticPresenceSimulation
オプションの値を切り替えることでパスキー入力を手動でトリガーすると、前のアプローチで遭遇した問題、すなわちテストコードの可読性の問題を解決できます。
ケース1:成功したパスキー入力のシミュレーション
以下のコードスニペットは、成功したパスキー入力をシミュレートします。
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() ); ... });
このヘルパー関数は、初めて見るとかなり威圧的に感じるかもしれません。パスキー操作をシミュレートするための技術的な複雑さがすべてヘルパー関数に抽象化されていると理解すると助けになります。これは、テストコード内で使用されると、上記の2番目のコードスニペットでわかるように、コードがシンプルで明確になることを意味します。
セクション6.1.1の暗黙的なアプローチと比較して、この明示的なアプローチはコードの可読性も向上させます。これは、条件付きUIがプロンプトされる場合に特に役立ちます。この明示的なアプローチは、開発者の認識なしにパスキー操作が意図せず暗黙的に完了するのを防ぎます。
では、ヘルパー関数の各部分を理解しましょう。
まず、operationCompleted
プロミスを定義します。これはWebAuthn.credentialAdded
イベントまたはWebAuthn.credentialAsserted
イベントのいずれかを待ちます。これらのイベントは、名前が示すように、パスキー資格情報がそれぞれ登録または検証されたときに発行されます。このプロミスは後で使用されます。
次に、isUserVerified
オプションがtrue
に設定され、WebAuthn仮想認証器による後続のパスキー操作が成功するようになります。automaticPresenceSimulation
もtrue
に設定され、WebAuthn仮想認証器がウェブページからの次のパスキープロンプトに応答するようになります。
operationTrigger
プロミスを待機することは、競合状態を避けるために必要です。競合状態は、automaticPresenceSimulation
がtrue
に設定される前にウェブページがパスキーを要求した場合に発生します。これを防ぐために、パスキープロンプトをトリガーするユーザーアクションは、automaticPresenceSimulation
がtrue
に設定された後に実行する必要があります。上記の例では、ユーザーは「Create
account with
passkeys」という名前のボタンをクリックしてパスキープロンプトをトリガーします。
ユーザーアクションが完了した後、成功したパスキー操作が完了するのを待つ必要があります。これは、ヘルパー関数の冒頭で定義したプロミスを待機することで行われます。成功したパスキー操作の完了は、WebAuthn.credentialAdded
またはWebAuthn.credentialAsserted
イベントの発行によって示されます。上記の例では、ユーザーがパスキーを登録しているため、WebAuthn.credentialAdded
イベントが発行されます。
最後に、automaticPresenceSimulation
オプションがfalse
に戻され、テストコードの後半で意図しないパスキー操作が発生するのを防ぎます。
ケース2:キャンセルされたパスキー入力のシミュレーション
キャンセルされたパスキー入力の場合、前のケースの実装にわずかな変更を加える必要があります。成功したパスキー入力の場合、操作の完了時に発行されるWebAuthn.credentialAdded
やWebAuthn.credentialAsserted
といったイベントがあります。しかし、WebAuthn仮想認証器は、キャンセルまたは失敗したパスキー入力に対するイベントを提供しません。したがって、キャンセルまたは失敗したパスキー操作の完了を確認するには、別の方法を使用する必要があります。
以下のコードスニペットは、失敗したパスキー入力をシミュレートします。
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 ... });
ヘルパー関数では、イベントリスナーがpostOperationCheck
というプロミスパラメータに置き換えられています。これは、automaticPresenceSimulation
をfalse
に戻す前に、期待されるUIの変更が発生するのを待ちます。
テストコードでは、唯一の違いは、意図したUIの変更をチェックする追加のプロミスを付けてヘルパー関数を呼び出す必要があることです。上記の例では、ウェブアプリケーションがヘッダーに「Something went wrong...」というテキストを持つページに正常にナビゲートしたことを確認します。
セクション6.1.1で説明したように、パスキー入力をキャンセルしても、UIに観察可能な変更が生じない場合があります。そのセクションで提供された例のように、そのような場合には、UIが実際に同じままであることを確認する前に、固定の待機時間を追加する必要があります。
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'); } ); ... });
WebAuthn仮想認証器を使用する利便性は、ウェブアプリケーションによるパスキーの作成や削除の際に、実際の認証器のように振る舞う能力によって高められます。テストは、ウェブアプリケーション上でパスキーの作成や削除をシミュレートするユーザーアクションを実行するだけでよく、WebAuthn仮想認証器は、テストコード側で追加の作業を行うことなく、保存されている資格情報情報を自動的に変更します。
以下は、ウェブアプリケーションが新しいパスキーを認証器に正しく登録することをチェックするテストコードの例です。
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); ... });
このコードスニペットをセクション6.1のコードスニペットと組み合わせることで、私たちのデモウェブページでサインアップフローをテストできます。次のビデオは、PlaywrightのUIモードでのテストの視覚化です。
WebAuthn仮想認証器でパスキー資格情報を検証することは、パスキーの作成と同様に機能します。仮想認証器は、特定の資格情報を使用して実行された検証の回数を自動的に追跡します。
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); ... });
次のビデオは、私たちのデモウェブページでのログインフローのテストを示しています。
一方、ウェブアプリケーションからパスキーを削除しても、WebAuthn仮想認証器内の情報は変更されるべきではありません。ウェブアプリケーションは、自身のサーバーに保存されている資格情報のみを削除できるべきです。ユーザー自身だけが、意識的かつ手動で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); ... });
次のビデオは、私たちのデモウェブページでのパスキー資格情報の削除テストを示しています。
2台目のデバイス(まだパスキーが登録されていない)からのクロスデバイス認証をシミュレートする最も直感的な方法は、CDPコマンドを介してWebAuthn仮想認証器の新しいインスタンスを単純に追加することです。
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 .. });
複数の仮想認証器のIDを管理する複雑さを避けるために、単一の認証器から資格情報を削除し、必要に応じて再度追加することで新しいデバイスをシミュレートすることも可能です。
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 ... });
このアプローチは、新しいデバイスをシミュレートする必要があるが、古いデバイスをもう使用する必要がない場合に特に実装を簡素化できます。この場合、仮想認証器から資格情報をクリアし、その資格情報を完全に破棄するだけで済みます。
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 ... });
WebAuthn仮想認証器の代替手段を探ることで、プロジェクト内でパスキー/WebAuthn認証プロセスをどのようにテストするかに柔軟性をもたらすことができます。
モックサービスやエンドポイントを開発することで、認証の振る舞いを効果的にシミュレートし、実際の認証メカニズムの複雑さを抽象化してテストを簡素化できます。このアプローチは、外部の認証サービスが使用されている場合に特に有益であり、認証の詳細に立ち入ることなく、システムコンポーネントの統合と機能性に焦点を当てることができます。
認証機能を徹底的に調査するためには、統合テストに実際の認証器を使用することで、ハードウェアセキュリティキー(例:YubiKeys)や生体認証デバイス(例:Face ID、Touch ID、Windows Helloで使用)との相互作用に関する詳細な洞察が得られます。実際のデバイスを自動テストに統合するのは複雑な性質のため、通常は手動で行われますが、カスタムの自動化スクリプトを開発することは可能です。これらのスクリプトは、実際の認証器とエンドツーエンドのテストフレームワークを橋渡しすることができ、実際のユーザーシナリオにより近い近似を提供し、本番環境での認証プロセスの信頼性を高めます。
Playwrightを用いたパスキー/WebAuthnのE2Eテストに関するさまざまなオプションを示し、特定のコードスニペットを紹介した後、このトピックに不慣れな開発者向けに、より一般的な推奨事項も提供したいと思います。
パスキーやその他の認証メカニズムのテストに飛び込む前に、利用可能なE2Eテストフレームワークを評価し、プロジェクトの要件に応じて最も適切なオプションを選択することが不可欠です。PlaywrightやPuppeteerのようなCDPベースのフレームワークが提供する速度と安定性、そしてSeleniumやNightwatchのようなWebDriverベースのフレームワークが提供するクロスブラウザ互換性との間のトレードオフを考慮してください。CDPベースのフレームワークはより高速で安定したブラウザ自動化を提供しますが、Chromiumベースのブラウザに限定されます。対照的に、WebDriverベースのフレームワークは、FirefoxやSafariなどの非Chromiumブラウザを含む、より広範なクロスブラウザ互換性を提供しますが、パフォーマンスが遅く不安定になる可能性があります。これらのトレードオフを理解することで、情報に基づいた決定を下し、プロジェクトのニーズに最も適したフレームワークを選択するのに役立ちます。
WebAuthn仮想認証器はパスキー実装のテストプロセスを簡素化しますが、開発者がWebAuthn標準とパスキーの背後にある基本概念をしっかりと理解していることが重要です。プロトコル、トランスポート、hasResidentKey、hasUserVerification、isUserVerifiedなど、WebAuthn仮想認証器で利用可能なさまざまな設定に精通してください。これらの設定を理解することで、さまざまな認証シナリオを正確にシミュレートするために仮想認証器を微調整できるようになります。さらに、さまざまなブラウザやデバイスとの統合、潜在的なセキュリティ上の考慮事項など、パスキー認証の複雑さを深く掘り下げてください。この基礎知識は、ウェブアプリケーションでパスキー認証のための包括的で効果的なテスト戦略を設計する力を与えてくれます。
このガイドでは、PlaywrightでCDP WebAuthn仮想認証器を使用する方法を掘り下げ、公式ドキュメントでカバーされていない高度な概念や問題点に焦点を当てました。また、Playwright内のCDPや他のE2Eテストフレームワークの代替手段も探りました。実装はさまざまですが、標準化されたWebAuthn仮想認証器の仕様により、このガイドはさまざまなウェブ自動化プロトコルやエンドツーエンドのテストフレームワークにわたって関連性を持ちます。パスキーに関するさまざまな概念についてより深く学ぶには、ニーズに基づいてWebAuthn仮想認証器を微調整するのに役立つ可能性のある関連用語の用語集を参照してください。
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