Slide 1

Slide 1 text

Copyright © Yoshikazu Nojima 2025 サーバーサイド開発者のためのパスキー入門 2025-02-13 パスキー開発者の集い 能島 良和 (@shiroica)

Slide 2

Slide 2 text

Copyright © Yoshikazu Nojima 2024 自己紹介 • 能島良和 • Red Hatでミドルウェア製品のテクニカルサポートを担当 • WebAuthn4Jというライブラリの開発者 https://github.com/webauthn4j/webauthn4j Keycloak、Spring、Quarkus等で採用 • Twitter:@shiroica • GitHub:ynojima 1

Slide 3

Slide 3 text

Copyright © Yoshikazu Nojima 2024 目次 • パスキーの処理の概要 • サーバーサイドで必要な処理 • ライブラリ・フレームワークが提供する処理 • アプリケーション側で必要な実装 • Javaでの実装例 • Spring • Quarkus 2

Slide 4

Slide 4 text

Copyright © Yoshikazu Nojima 2024 パスキー処理の概要 3

Slide 5

Slide 5 text

Copyright © Yoshikazu Nojima 2024 デモ 4

Slide 6

Slide 6 text

Copyright © Yoshikazu Nojima 2024 クレデンシャル の保存 パスキーの登録フロー(概要) パスキープロバイダ ブラウザ サーバー • Credential Id • Authenticator data • 署名 を送信 クレデンシャル(Credential Id, Authenticator data, Client Data, 署名、etc.)を送信 Client dataのハッシュを送信 Authenticator data(RpIdのハッシュ, フラグ,カウンタ,RP固有公開鍵,拡張)を生成 challengeを提供 Storage RP固有秘密鍵 を保存 Client data (challenge, origin, etc.)を生成 Client dataのハッシュと Authenticator dataに対する署名を生成 challenge を生成・保存 challenge の読込 RP固有鍵ペアを生成 クレデンシャルに対し、 ドメイン(RP Id)、署名、 challenge、その他の検証 DB Session

Slide 7

Slide 7 text

Copyright © Yoshikazu Nojima 2024 クレデンシャル の読込 パスキーの認証フロー(概要) パスキープロバイダ ブラウザ サーバー • Credential Id • Authenticator data • 署名 を送信 アサーション(Credential Id, Authenticator data, Client Data, 署名、etc.)を送信 Client dataのハッシュを送信 Authenticator data(RpIdのハッシュ, フラグ,カウンタ,拡張)を生成 Storage RP固有秘密鍵 を読込 Client data (challenge, origin, etc.)を生成 Client dataのハッシュと Authenticator dataに対する署名を生成 challenge の読込 クレデンシャルに対し、 ドメイン(RP Id)、署名、 challenge、その他の検証 DB Session challengeを提供 challenge を生成・保存

Slide 8

Slide 8 text

Copyright © Yoshikazu Nojima 2024 クレデンシャル (公開鍵)の読込 プロトコルレベルで組み込まれたセキュリティ(1): クレデンシャル流出対策としての公開鍵認証 パスキープロバイダ ブラウザ サーバー • Credential Id • Authenticator data • 署名 を送信 アサーション(Credential Id, Authenticator data, Client Data, 署名、etc.)を送信 Client dataのハッシュを送信 Authenticator data(RpIdのハッシュ, フラグ,カウンタ,拡張)を生成 Storage RP固有秘密鍵 を読込 Client data (challenge, origin, etc.)を生成 Client dataのハッシュと Authenticator dataに対する署名を生成 challenge の読込 クレデンシャルに対し、 ドメイン(RP Id)、署名、 challenge、その他の検証 DB Session challengeを提供 challenge を生成・保存 サーバーに保存されているのは公開鍵、 通信経路でやり取りされるのは署名なので流出しても影響は軽減

Slide 9

Slide 9 text

Copyright © Yoshikazu Nojima 2024 クレデンシャル の読込 プロトコルレベルで組み込まれたセキュリティ(2): リプレイ攻撃対策としてのチャレンジデータ パスキープロバイダ ブラウザ サーバー • Credential Id • Authenticator data • 署名 を送信 アサーション(Credential Id, Authenticator data, Client Data, 署名、etc.)を送信 Client dataのハッシュを送信 Authenticator data(RpIdのハッシュ, フラグ,カウンタ,拡張)を生成 Storage RP固有秘密鍵 を読込 Client data (challenge, origin, etc.)を生成 Client dataのハッシュと Authenticator dataに対する署名を生成 challenge の読込 クレデンシャルに対し、 ドメイン(RP Id)、署名、 challenge、その他の検証 DB Session challengeを提供 challenge を生成・保存 署名対象にチャレンジ(ランダムデータ)を含めることで、 詐取した正規のリクエストを繰り返すリプレイ攻撃を防止

Slide 10

Slide 10 text

Copyright © Yoshikazu Nojima 2024 クレデンシャル の保存 WebAuthn APIが提供する範囲(登録処理) パスキープロバイダ ブラウザ サーバー • Credential Id • Authenticator data • 署名 を送信 クレデンシャル(Credential Id, Authenticator data, Client Data, 署名、etc.)を送信 Client dataのハッシュを送信 Authenticator data(RpIdのハッシュ, フラグ,カウンタ,RP固有公開鍵,拡張)を生成 challengeを提供 Storage RP固有秘密鍵 を保存 Client data (challenge, origin, etc.)を生成 Client dataのハッシュと Authenticator dataに対する署名を生成 challenge の読込 RP固有鍵ペアを生成 クレデンシャルに対し、 ドメイン(RP Id)、署名、 challenge、その他の検証 DB Session navigator.credentials.create() challenge を生成・保存

Slide 11

Slide 11 text

Copyright © Yoshikazu Nojima 2024 クレデンシャル の読込 WebAuthn APIが提供する範囲(認証処理) パスキープロバイダ ブラウザ サーバー • Credential Id • Authenticator data • 署名 を送信 アサーション(Credential Id, Authenticator data, Client Data, 署名、etc.)を送信 Client dataのハッシュを送信 Authenticator data(RpIdのハッシュ, フラグ,カウンタ,拡張)を生成 Storage RP固有秘密鍵 を読込 Client data (challenge, origin, etc.)を生成 Client dataのハッシュと Authenticator dataに対する署名を生成 challenge の読込 クレデンシャルに対し、 ドメイン(RP Id)、署名、 challenge、その他の検証 DB Session challengeを提供 navigator.credentials.get() challenge を生成・保存

Slide 12

Slide 12 text

Copyright © Yoshikazu Nojima 2024 サーバーサイドで必要な処理 11

Slide 13

Slide 13 text

Copyright © Yoshikazu Nojima 2024 クレデンシャル の保存 サーバーサイドで必要な処理(登録フロー) パスキープロバイダ ブラウザ サーバー • Credential Id • Authenticator data • 署名 を送信 クレデンシャル(Credential Id, Authenticator data, Client Data, 署名、etc.)を送信 Client dataのハッシュを送信 Authenticator data(RpIdのハッシュ, フラグ,カウンタ,RP固有公開鍵,拡張)を生成 challengeを提供 Storage RP固有秘密鍵 を保存 Client data (challenge, origin, etc.)を生成 Client dataのハッシュと Authenticator dataに対する署名を生成 challenge の読込 RP固有鍵ペアを生成 クレデンシャルに対し、 ドメイン(RP Id)、署名、 challenge、その他の検証 DB Session チャレンジ提供用エンドポイント クレデンシャル登録用エンドポイント challenge を生成・保存

Slide 14

Slide 14 text

Copyright © Yoshikazu Nojima 2024 クレデンシャル の読込 サーバーサイドで必要な処理(認証フロー) パスキープロバイダ ブラウザ サーバー • Credential Id • Authenticator data • 署名 を送信 アサーション(Credential Id, Authenticator data, Client Data, 署名、etc.)を送信 Client dataのハッシュを送信 Authenticator data(RpIdのハッシュ, フラグ,カウンタ,拡張)を生成 Storage RP固有秘密鍵 を読込 Client data (challenge, origin, etc.)を生成 Client dataのハッシュと Authenticator dataに対する署名を生成 challenge の読込 クレデンシャルに対し、 ドメイン(RP Id)、署名、 challenge、その他の検証 DB Session challengeを提供 チャレンジ提供用エンドポイント アサーション認証用エンドポイント challenge を生成・保存

Slide 15

Slide 15 text

Copyright © Yoshikazu Nojima 2024 ライブラリ・フレームワークが 提供する機能 14

Slide 16

Slide 16 text

Copyright © Yoshikazu Nojima 2024 クレデンシャル の読込 エンドポイント含めて提供するフレームワークの場合 パスキープロバイダ ブラウザ サーバー • Credential Id • Authenticator data • 署名 を送信 アサーション(Credential Id, Authenticator data, Client Data, 署名、etc.)を送信 Client dataのハッシュを送信 Authenticator data(RpIdのハッシュ, フラグ,カウンタ,拡張)を生成 Storage RP固有秘密鍵 を読込 Client data (challenge, origin, etc.)を生成 Client dataのハッシュと Authenticator dataに対する署名を生成 challenge の読込 クレデンシャルに対し、 ドメイン(RP Id)、署名、 challenge、その他の検証 DB Session challengeを提供 challenge を生成・保存 エンドポイント含め提供 エンドポイント含め提供

Slide 17

Slide 17 text

Copyright © Yoshikazu Nojima 2024 クレデンシャル の読込 クレデンシャル検証のみを提供するライブラリの場合 パスキープロバイダ ブラウザ サーバー • Credential Id • Authenticator data • 署名 を送信 アサーション(Credential Id, Authenticator data, Client Data, 署名、etc.)を送信 Client dataのハッシュを送信 Authenticator data(RpIdのハッシュ, フラグ,カウンタ,拡張)を生成 Storage RP固有秘密鍵 を読込 Client data (challenge, origin, etc.)を生成 Client dataのハッシュと Authenticator dataに対する署名を生成 challenge の読込 クレデンシャルに対し、 ドメイン(RP Id)、署名、 challenge、その他の検証 DB Session challengeを提供 challenge を生成・保存 検証処理のみを提供

Slide 18

Slide 18 text

Copyright © Yoshikazu Nojima 2024 アプリケーション側で必要な実装 17

Slide 19

Slide 19 text

Copyright © Yoshikazu Nojima 2024 クレデンシャル の読込 検証処理のみを提供するライブラリの場合の アプリケーション側で必要な実装 パスキープロバイダ ブラウザ サーバー • Credential Id • Authenticator data • 署名 を送信 アサーション(Credential Id, Authenticator data, Client Data, 署名、etc.)を送信 Client dataのハッシュを送信 Authenticator data(RpIdのハッシュ, フラグ,カウンタ,拡張)を生成 Storage RP固有秘密鍵 を読込 Client data (challenge, origin, etc.)を生成 Client dataのハッシュと Authenticator dataに対する署名を生成 challenge の読込 クレデンシャルに対し、 ドメイン(RP Id)、署名、 challenge、その他の検証 DB Session challengeを提供 challenge を生成・保存 アプリとして実装が必要 アプリとして実装が必要 検証処理のみを提供

Slide 20

Slide 20 text

Copyright © Yoshikazu Nojima 2024 クレデンシャル の読込 フレームワークに特化したラッパーライブラリが 提供さている場合に必要な実装 パスキープロバイダ ブラウザ サーバー • Credential Id • Authenticator data • 署名 を送信 アサーション(Credential Id, Authenticator data, Client Data, 署名、etc.)を送信 Client dataのハッシュを送信 Authenticator data(RpIdのハッシュ, フラグ,カウンタ,拡張)を生成 Storage RP固有秘密鍵 を読込 Client data (challenge, origin, etc.)を生成 Client dataのハッシュと Authenticator dataに対する署名を生成 challenge の読込 クレデンシャルに対し、 ドメイン(RP Id)、署名、 challenge、その他の検証 DB Session challengeを提供 challenge を生成・保存 ラッパーライブラリが提供 ラッパーライブラリが提供 検証処理のみを提供 アプリとして実装が必要

Slide 21

Slide 21 text

Copyright © Yoshikazu Nojima 2024 クレデンシャル の読込 例:Spring/Quarkus パスキープロバイダ ブラウザ サーバー • Credential Id • Authenticator data • 署名 を送信 アサーション(Credential Id, Authenticator data, Client Data, 署名、etc.)を送信 Client dataのハッシュを送信 Authenticator data(RpIdのハッシュ, フラグ,カウンタ,拡張)を生成 Storage RP固有秘密鍵 を読込 Client data (challenge, origin, etc.)を生成 Client dataのハッシュと Authenticator dataに対する署名を生成 challenge の読込 クレデンシャルに対し、 ドメイン(RP Id)、署名、 challenge、その他の検証 DB Session challengeを提供 challenge を生成・保存 Spring Security/Quarkus Securityが提供 Spring Security/Quarkus Securityが提供 WebAuthn4Jが提供 アプリとして実装が必要

Slide 22

Slide 22 text

Copyright © Yoshikazu Nojima 2024 Quarkusでの実装例 21

Slide 23

Slide 23 text

Copyright © Yoshikazu Nojima 2024 Quarkusとは 22

Slide 24

Slide 24 text

Copyright © Yoshikazu Nojima 2024 code.quarkus.ioでプロジェクト生成 23

Slide 25

Slide 25 text

Copyright © Yoshikazu Nojima 2024 クレデンシャル の読込 おさらい: Quarkus Security WebAuthnで必要な実装箇所 パスキープロバイダ ブラウザ サーバー • Credential Id • Authenticator data • 署名 を送信 アサーション(Credential Id, Authenticator data, Client Data, 署名、etc.)を送信 Client dataのハッシュを送信 Authenticator data(RpIdのハッシュ, フラグ,カウンタ,拡張)を生成 Storage RP固有秘密鍵 を読込 Client data (challenge, origin, etc.)を生成 Client dataのハッシュと Authenticator dataに対する署名を生成 challenge の読込 クレデンシャルに対し、 ドメイン(RP Id)、署名、 challenge、その他の検証 DB Session challengeを提供 challenge を生成・保存 Quarkus Securityが提供 Quarkus Securityが提供 WebAuthn4Jが提供 アプリとして実装が必要

Slide 26

Slide 26 text

Copyright © Yoshikazu Nojima 2024 エンドポイントの有効化のための application.propertiesでの設定 25 quarkus.webauthn.login-page=/ quarkus.webauthn.enable-login-endpoint=true quarkus.webauthn.enable-registration-endpoint=true

Slide 27

Slide 27 text

Copyright © Yoshikazu Nojima 2024 クレデンシャルの永続化処理のために WebAuthnUserProviderインタフェースを実装 26 @Blocking @ApplicationScoped public class DemoWebAuthnUserProvider implements WebAuthnUserProvider { private final List credentialRecords = new ArrayList<>(); @Override public Uni> findByUsername(String username) { return Uni.createFrom().item(credentialRecords.stream() .filter(record -> record.getUsername().equals(username)).collect(Collectors.toList())); } @Override public Uni findByCredentialId(String credentialId) { return Uni.createFrom().item(credentialRecords.stream() .filter(record -> record.getCredentialID().equals(credentialId)) .findFirst().orElseThrow(()-> new RuntimeException("credential not found"))); } @Override public Uni update(String credentialId, long counter) { findByCredentialId(credentialId).subscribe().with(credentialRecord -> credentialRecord.setCounter(counter)); return Uni.createFrom().voidItem(); } @Override public Uni store(WebAuthnCredentialRecord credentialRecord) { credentialRecords.add(credentialRecord); return Uni.createFrom().voidItem(); } }

Slide 28

Slide 28 text

Copyright © Yoshikazu Nojima 2024 エンドポイントの動作 $ curl http://localhost:8080/q/webauthn/register-options-challenge?username=ynojima { "rp": { "id": "localhost", "name": "Quarkus server" }, "user": { "id": "Baeobf2jRmqbFa1nLz_rDg", "name": "ynojima", "displayName": "ynojima" }, "challenge": "nLZXvZrAz2rTU0erERIGrRsqY3zl8bW57-IUmzPzEX2FSR50yrGKWy-QPsMtDy6y6y9TWXOlf- _AcQZNSg6wWQ", "pubKeyCredParams": [ { "type": "public-key", "alg": -7 }, { "type": "public-key", "alg": -257} ], "timeout": 300000, "excludeCredentials": [], "authenticatorSelection": { "requireResidentKey": true, "residentKey": "required", "userVerification": "required" }, "attestation": "none", "extensions": {} } 27

Slide 29

Slide 29 text

Copyright © Yoshikazu Nojima 2024 クレデンシャル の保存 登録処理の全体像 パスキープロバイダ ブラウザ サーバー • Credential Id • Authenticator data • 署名 を送信 クレデンシャル(Credential Id, Authenticator data, Client Data, 署名、etc.)を送信 Client dataのハッシュを送信 Authenticator data(RpIdのハッシュ, フラグ,カウンタ,RP固有公開鍵,拡張)を生成 challengeを提供 Storage RP固有秘密鍵 を保存 Client data (challenge, origin, etc.)を生成 Client dataのハッシュと Authenticator dataに対する署名を生成 challenge の読込 RP固有鍵ペアを生成 クレデンシャルに対し、 ドメイン(RP Id)、署名、 challenge、その他の検証 DB Session チャレンジ提供用エンドポイント クレデンシャル登録用エンドポイント challenge を生成・保存 navigator.credentials.create() フロントエンド 呼出 呼出 呼出

Slide 30

Slide 30 text

Copyright © Yoshikazu Nojima 2024 フロントエンドの実装例 29 async function createCredential(username){ // オプション(含チャレンジ)提供用エンドポイントの呼出 const registerOptionsChallengeEndpoint = username ? `/q/webauthn/register-options-challenge?username=${encodeURIComponent(username)}` : “/q/webauthn/register-options-challenge” const response = await fetch(registerOptionsChallengeEndpoint) const publicKeyCredentialCreationOptionsJSON = await response.json() const credentialCreationOptions = PublicKeyCredential.parseCreationOptionsFromJSON(publicKeyCredentialCreationOptionsJSON); // パスキークレデンシャルの作成 const publicKeyCredential = await navigator.credentials.create({ publicKey: credentialCreationOptions}); const registrationResponseJSON = publicKeyCredential.toJSON(); console.log(registrationResponseJSON); // クレデンシャル登録用エンドポイントの呼出 const registerEndpoint = username ? `/q/webauthn/register?username=${encodeURIComponent(username)}` : “/q/webauthn/register” await fetch(registerEndpoint, { method : 'POST', body: JSON.stringify(registrationResponseJSON) }); } ※PublicKeyCredential.parseCreationOptionsFromJSON, PublicKeyCredential#toJSON メソッドはSafariで2025/01現在未実装なので注意。github/webauthn-jsonのようなPolyfillが必須

Slide 31

Slide 31 text

Copyright © Yoshikazu Nojima 2024 クレデンシャル の読込 認証処理の全体像 パスキープロバイダ ブラウザ サーバー • Credential Id • Authenticator data • 署名 を送信 アサーション(Credential Id, Authenticator data, Client Data, 署名、etc.)を送信 Client dataのハッシュを送信 Authenticator data(RpIdのハッシュ, フラグ,カウンタ,拡張)を生成 Storage RP固有秘密鍵 を読込 Client data (challenge, origin, etc.)を生成 Client dataのハッシュと Authenticator dataに対する署名を生成 challenge の読込 クレデンシャルに対し、 ドメイン(RP Id)、署名、 challenge、その他の検証 DB Session challengeを提供 チャレンジ提供用エンドポイント アサーション認証用エンドポイント challenge を生成・保存 navigator.credentials.get() フロントエンド 呼出 呼出 呼出

Slide 32

Slide 32 text

Copyright © Yoshikazu Nojima 2024 実装例 31

Slide 33

Slide 33 text

Copyright © Yoshikazu Nojima 2024 ※登録エンドポイントの独自実装が必要なケース • QuarkusやSpringといった、フレームワークが提供する 標準のパスキー登録エンドポイントは、パスキーの登録のみが可能 • 1回のフォームPOSTで、ユーザーの氏名や住所等、ユーザーアカウントの 他の属性も登録したい場合、標準の登録エンドポイントでは対応不可能 • 独自のエンドポイントを実装し、受け取ったパスキーのクレデンシャルの 検証処理を呼び出す必要有 32

Slide 34

Slide 34 text

Copyright © Yoshikazu Nojima 2024 リファレンス • Quarkus公式のquickstartプロジェクト • https://github.com/quarkusio/quarkus-quickstarts/tree/main/security-webauthn-quickstart • Quarkus公式のSecurity WebAuthnのガイド • https://quarkus.io/guides/security-webauthn • Spring公式のPasskeysのガイド • https://docs.spring.io/spring-security/reference/servlet/authentication/passkeys.html 33

Slide 35

Slide 35 text

Copyright © Yoshikazu Nojima 2024 まとめ 34

Slide 36

Slide 36 text

Copyright © Yoshikazu Nojima 2024 まとめ • パスキー認証の登録・認証処理のシーケンスの全体像を説明しました • パスキー認証の実装には、サーバーサイドはチャレンジの提供や、 クレデンシャルの登録、認証等のエンドポイントの提供が必要 • ライブラリによって提供する機能は、 検証処理だけ、エンドポイントも提供、DBへの永続化処理も提供、と様々 • ライブラリを選定する際は、利用しているフレームワークにおいて どこまでの機能を提供してくれるのか、自らのユースケースにあうのか、 がポイントの一つです 35

Slide 37

Slide 37 text

Copyright © Yoshikazu Nojima 2024 Appendix 36

Slide 38

Slide 38 text

Copyright © Yoshikazu Nojima 2024 パスキー実装時の悩み 37 どうやって自動テスト書く?

Slide 39

Slide 39 text

Copyright © Yoshikazu Nojima 2024 E2Eテストで扱う典型的な認証フロー(パスワード認証) 1. 登録画面に遷移する 2. 登録画面でユーザー名と パスワードを入力する 3. 登録ボタンを押す 4. 認証画面に遷移する 5. 認証画面でユーザー名と パスワードを入力する 6. 認証画面で認証ボタンを押す 38 自動化は容易

Slide 40

Slide 40 text

Copyright © Yoshikazu Nojima 2024 E2Eテストで扱う典型的な認証フロー(パスキー認証) 1. 登録画面に遷移する 2. 登録画面でユーザー名を入力する 3. パスキーの登録ボタンを押す 4. パスキープロバイダー側で承認操作を行う 5. 登録ボタンを押す 6. 認証画面に遷移する 7. 認証画面で認証ボタンを押す 8. パスキープロバイダーで承認操作を行う 39

Slide 41

Slide 41 text

Copyright © Yoshikazu Nojima 2024 E2Eテストで扱う典型的な認証フロー(パスキー認証) 1. 登録画面に遷移する 2. 登録画面でユーザー名を入力する 3. パスキーの登録ボタンを押す 4. パスキープロバイダー側で承認操作を行う 5. 登録ボタンを押す 6. 認証画面に遷移する 7. 認証画面で認証ボタンを押す 8. パスキープロバイダーで認証操作を行う 40 手動操作が必要

Slide 42

Slide 42 text

Copyright © Yoshikazu Nojima 2024 41 承認操作なしで応答を返す、 エミュレーターが欲しい

Slide 43

Slide 43 text

Copyright © Yoshikazu Nojima 2024 Chromeの開発者ツール 42 Chromeの開発者ツール のWebAuthnタブから、 仮想Authenticatorの 追加削除が可能

Slide 44

Slide 44 text

Copyright © Yoshikazu Nojima 2024 WebAuthn WebDriver Extension WebDriver APIで操作されているブラウザに対し、 Authenticatorのエミュレータを追加・削除するための拡張API 43

Slide 45

Slide 45 text

Copyright © Yoshikazu Nojima 2024 selenium-javaでのテストコード例 44 public class RegistrationAndAuthenticationE2ETest extends E2ETestBase{ @Test public void test() { VirtualAuthenticatorOptions options = new VirtualAuthenticatorOptions(); ((HasVirtualAuthenticator) driver).addVirtualAuthenticator(options); // Registration SignupComponent signupComponent = new SignupComponent(driver); signupComponent.navigate(); signupComponent.setFirstname(“John”); signupComponent.setLastname(“Doe”); signupComponent.setUsername(“[email protected]”); signupComponent.setPassword(“password”); signupComponent.clickAddAuthenticator(); signupComponent.getResidentKeyRequirementDialog().clickNo(); signupComponent.waitRegisterClickable(); signupComponent.clickRegister(); // Password authentication wait.until(ExpectedConditions.urlToBe(“http://localhost:8080/angular/login”)); PasswordLoginComponent passwordLoginComponent = new PasswordLoginComponent(driver); passwordLoginComponent.setUsername(“[email protected]”); passwordLoginComponent.setPassword(“password”); passwordLoginComponent.clickLogin(); // 2nd-factor authentication AuthenticatorLoginComponent authenticatorLoginComponent = new AuthenticatorLoginComponent(driver); // nop wait.until(ExpectedConditions.urlToBe(“http://localhost:8080/angular/profile”)); } テストコード自体は ページオブジェクト パターンに則った Seleniumの普通の テストコード 仮想Authenticator追加

Slide 46

Slide 46 text

Copyright © Yoshikazu Nojima 2024 Chromiumの仮想Authenticatorで十分か? • 仮想Authenticatorの設定項目は多くない (residentKey, uv, transport等) • 残念ながらパスキーは環境依存の問題が発生しがち • ChromeでのE2Eテストは、よく使われる環境をカバー出来、 テスト効率を向上させるが、依然として手動テストも重要 45

Slide 47

Slide 47 text

Copyright © Yoshikazu Nojima 2024 まとめ • パスキーはパスキープロバイダーでユーザーの承認操作が必要 • E2Eテストを自動化する上で承認操作が障害 • ChromeはWebAuthn WebDriver Extension APIを通じて 仮想Authenticatorに実装を切替、承認ジェスチャーをスキップ可能 • Chrome以外をカバーするために手動テストも依然として必要 • パスキーでも諦めずにE2Eテストを書いていきましょう! 46