
想定している読者
パスキーの導入に興味のある開発者
この記事で前提としているKeycloakのバージョン
24.0.2
パスキー認証とは
パスキーとは、パスワードに代わるFIDO認証の資格情報(クレデンシャル)です。
FIDO(Fast Identity Online)とは、従来のパスワードに代わる認証手段として期待される技術で、FIDO Allianceによって規格の策定と普及が進められています。
OSプラットフォーム主要3社(Apple、Google、Microsoft)とFIDO Allianceが協力して推進しており、今後主流になると予想されている認証方式です。
パスキー認証は公開鍵暗号方式を採用しています。
サービス利用開始のタイミング等で利用デバイスで秘密鍵・公開鍵のペア(パスキー)を作成します。
利用デバイスで秘密鍵を、認証サーバーで公開鍵を保持します。

サーバに保存されるのは公開鍵のみとなるため、仮にサーバ側から公開鍵が流出したとして、適切な署名データを作ることはできず、なりすましによる攻撃を防ぐことができます。
また、秘密鍵はサイトの情報に紐づいて作成されるため、フィッシングサイトにログインを試みた際は紐づいたパスキーが存在せず、認証処理が中断されます。
パスキーの壁
直面した課題
パスキーとは何かを理解する際に、最初に「パスキー=生体認証」という誤解があり、生体情報の利用方法を調べても有益な情報が見つかりませんでした。(実際には、生体情報はパスキーに直接利用されません)
パスキーに関して調査を進めると、パスワードレス認証、FIDO2、WebAuthn、同期パスキー、デバイスバウンドパスキーなど、さまざまな用語が出てきて、パスキーが具体的に何を指すのか理解するのが難しいという課題がありました。
克服方法
まずは、パスキーを実際に利用して、その実態を体感しました。パスキーは状況によって認証方式や鍵ペア(公開鍵・秘密鍵)を意味することがあります。
実際に利用することで、「パスキー」という用語が複数の概念を指していることが感覚的に理解できました。
パスキーを利用してみる
パスキーデモサイト
パスキーについてデモサイト(Passkeys.io)で体験していただけます。
一般的なサイト
一般的なサイトでもパスキーが利用できるサイトがありますが、それぞれ UIや対応OS、対応ブラウザが異なります。
※いずれもWindows 10で検証。
ID入力後にパスキー認証するサイトの例
Adobe
Docomo
Google
Yahoo! JAPAN
パスキーのみで認証するサイトの例
GitHub
Microsoft
Nintendo
Passkey.io(パスキーデモサイト)
Windows 10に対応していないサイトの例
Amazon
Apple
au
LaKeel DXは利便性向上のためパスキーのみで認証する方式を採用しています。Keycloak ではパスキーのみで認証する方式をログインレス認証、ID+パスキー認証する方式をパスワードレス認証と呼びます。
パスキー導入時の補足
Windows Helloが利用できない
弊社のグループポリシーでは、Windows Helloが利用できないため、Windows PCでパスキーが利用できませんでした。

解決策
グループポリシーエディタで生体認証とWindows Hello for Business の利用を有効にすることで解決しました。

Keycloakのパスキー検証の苦労話①
Windows Helloを利用してパスキー認証できなかった
Keycloakのデフォルト設定では Windows Hello を利用したパスキー認証(※)ができませんでした。
※ Keycloak 26 では、デフォルトで Windows Hello によるパスキー認証ができるようになっています。
解決策
Keycloakのマニュアルに対応方法が書いてありました。
Keycloakの認証にWindows Helloベースの認証情報を使用するには、 WebAuthn Passwordless Policy の Signature Algorithms 設定に RS256 値を含めるよう設定します。
Keycloakのパスキー検証の苦労話②
ログインレス認証ができなかった
Keycloakのデフォルト設定では ログインレス認証ができませんでした。
※ Keycloak 26でも同様です。
解決策
管理コンソールの Authentication セクションの Policies → WebAuthn Passwordless Policy タブで設定を行います。ログインレスのシナリオのポリシーを設定する場合、 User Verification Requirement を required に、 Require Resident Key を Yes に設定する必要があります。

Keycloakの日本語マニュアル(Keycloak 22)では「Require Resident Key」と記載されていましたが、Keycloak 24以降は「Require Discoverable Credential」に名前が変わっています。
WebAuthnの仕様に合わせた変更だと思います。
Discoverable Credential
[DEPRECATED] Resident Credential
[DEPRECATED] Resident Key
パスワードレス認証とログインレス認証の違い
Keycloak のマニュアルでは、パスキー認証を大きく2つに分けています。
パスワードレス認証:パスワードの代わりにパスキーで認証する
ログインレス認証:ID+パスワードの代わりにパスキー認証する
パスワードレス認証ではIDの入力後にパスキー認証の画面に遷移します。
ログインレス認証ではID入力は不要となります。
利用者としてはID入力が不要になった方が便利だと思いますので、ログインレス認証の方が良さそうに思います。
一般的なサイトでのパスキー認証は、パスワードレス認証とログインレス認証は半々ぐらいです。(パスワードレス認証の方が少し多い印象です)
将来的にはログインレス認証が主流になるかも知れませんが、IDの入力が無くなると利用者は混乱するので、パスワードの代わりとしてパスワードレス認証が利用されていると推測しています。
認証しているのに「ログインレス」認証とはどういうことなのか、、
Keycloakの設定は「WebAuthn Passwordless」なのでパスワードレス?となってちょっと分かりづらいです。
WebAuthn Passwordless Policy の設定値
苦労話となるのですが、Keycloakのマニュアルには各項目の設定値について詳しくはW3Cの仕様を参照してくださいと記載されているので調べる必要がありました。
一部の設定値について調査結果を記載します。

Authenticator Attachment

Require discoverable credential
(Keycloak 23 以前の名称:Require resident Key)

User verification requirement

パスキー実装の課題
Keycloakテーマ問題
ロケールを日本語にしたとき、以下の問題がありました。
パスキー登録時のダイアログが英語になっています。
一部のラベルが「パスキー」でなく「セキュリティキー」になっています。(英語は「Passkey」となっています)
アカウント管理画面が全面的に英語表記となっています。

テーマの修正
パスキー登録時のダイアログのラベルはプロパティではなく、ログインテーマのソースコードに直接書かれているので、テーマファイルを修正しました。
let initLabel = "WebAuthn Authenticator (Default Label)";
let labelResult = window.prompt("Please input your registered authenticator's label", initLabel);
「セキュリティーキー」のラベルについては Localization の Realm overrides の設定で「パスキー」に修正しました。

パスキーの検証手順
実際にWindows上に環境構築してパスキーを検証する手順を記載します。
前提
Docker が利用できる環境(Docker Desktop など)を構築していること
Windows Hello に生体認証やPINを登録して利用可能になっていること
概要
サーバー、クライアントとも同一のWindows PC上でパスキーを検証します。
スマホからWindows上のKeycloakにアクセスしてパスキーを検証するにはhttpsでアクセスする必要があります。
httpsでアクセスするには自己証明書の作成やスマホに証明書の登録や信頼が必要になるため、ここでは割愛します。
Keycloak環境の構築
Windows でパスキーを検証するため、Keycloak 環境を構築します。
以下のコマンドを実行します。
docker run -p 8080:8080 -e KC_BOOTSTRAP_ADMIN_USERNAME=admin -e KC_BOOTSTRAP_ADMIN_PASSWORD=admin quay.io/keycloak/keycloak:26.0.7 start-dev
Keycloakにログイン
http://localhost:8080/ を開いて以下のID/PWでログインします。
Username: admin
Password: admin
検証用レルムの作成
Keycloak はデフォルトで master レルムが作成されますが、master の設定を間違えるとログインできなくなるため検証用レルムを作成します。
左上の master レルムをクリックしてプルダウンから「Create realm」ボタンをクリックします。

「Realm name」に「test」を入力して「Create」ボタンをクリックします。

認証フローの作成
「Authentication」>「Create flow」ボタンをクリックして「browser test」を作成します。

「Add execution」ボタンをクリックして「Cookie」を追加します。

「Add sub-flow」ボタンをクリックして「Username Password Form」サブフローを作成します。

「Username Password From」サブフローの+ボタン>「Add step」をクリックして「Username Password」を追加します。


「Add step」ボタンをクリックして「Webauthn Passwordless Authenticator」を追加します。

各ステップの Requirement を「Alternative」に変更します。

右上の「Action」プルダウンから「Bind flow」をクリックして「Browser flow」にバインドします。


テストユーザーの作成
「Users」>「Add user」ボタンをクリックして、テストユーザーを登録します。
「Username」「Email」「First name」「Last name」に値を入れます。
「Required user actions」に「Webauthn Register Passwordless」を指定します。
※ 初回ログイン時にパスキー登録が要求されるようになります。

「Credentials」タブ>「Set password」ボタンをクリックしてパスワードを設定します。
「Temporary」は「Off」にします。
※ On にすると初回ログイン時にパスワード変更が要求されるようになります。

アカウント管理にログインしてパスキーを登録
http://localhost:8080/realms/test/account/ を開いてテストユーザーのID/PWでログインします。
パスキーの登録が要求されるのでパスキーを登録します。

パスキーの名前を入力します。

アカウント管理にパスキーでログイン
一度ブラウザを閉じて再度 http://localhost:8080/realms/test/account/ を開きます。
「Try Another Way」ボタンをクリックします。

「Passkey」ボタンをクリックします。

「Sign in with Passkey」ボタンをクリックしてパスキーでログインできることを確認してください。

以上で、Windows上でKeycloakを使ったパスキーの検証手順が完了しました。パスキーを実際に設定してログインに使用することで、その効果とセキュリティ性能を実感できたのではないでしょうか。
終わりに
この記事を通じて、パスキーの導入過程で直面する可能性がある様々な課題とその解決策について、具体的な環境を例に挙げながらご紹介しました。パスキー導入は、セキュリティを強化しつつユーザー体験の向上を目指すうえで非常に有効な手段です。
このブログを参考に、パスキー導入の際の障壁を少しでもスムーズに乗り越えることができれば幸いです。
今後も、セキュリティにまつわる新たな情報や技術について発信していきますので、引き続きご期待ください。お読みいただき、ありがとうございました。