パスキーのユース ケース
このトピックでは、パスキーのユース ケースについて説明します。
ユース ケース 1: ブートストラップ
Web 上のアカウントのブートストラップ。
1.1: ユーザーの認証
このセクションは、証明書利用者 (RP) がクライアント デバイスを制御しているユーザーをまだ認識していない場合に適用されます。 RP で利用できるブラウザー成果物 (Cookie やローカル ストレージの資格情報 ID など) はありませんが、現時点では、ユーザーが RP を持つ既存のアカウントを持っていることを前提としています。
アカウントをブートストラップするには、ユーザーにサインイン ページを提供します。
まず、ユーザーに自分のアカウント識別子を要求します。通常はユーザー名または電子メール アドレスです。
パスキーのオートフィル UI をサポートするには、次の操作を行います。
- username入力フィールドの既存のオートコンプリート注釈に、
username
とwebauthn
の値を追加します。
<div>
<label for="username">Username:</label>
<input name="username" id="loginform.username"
autocomplete="username webauthn">
</div>
- ページの読み込み時に、
if
ステートメントを使用してオートフィル UI (条件付き仲介) が使用可能かどうかを確認し、mediation: "conditional"
とuserVerification: "preferred"
でnavigator.credentials.get()
を呼び出します。
<script>
(async () => {
if (
typeof window.PublicKeyCredential !== 'undefined'
&& typeof window.PublicKeyCredential.isConditionalMediationAvailable === 'function'
) {
const available = await PublicKeyCredential.isConditionalMediationAvailable();
if (available) {
try {
// Retrieve authentication options for `navigator.credentials.get()`
// from your server.
const authOptions = await getAuthenticationOptions();
// This call to `navigator.credentials.get()` is "set and forget."
// The Promise will resolve only if the user successfully interacts
// with the browser's autofill UI to select a passkey.
const webAuthnResponse = await navigator.credentials.get({
mediation: "conditional",
publicKey: {
...authOptions,
// See note about userVerification below.
userVerification: "preferred",
}
});
// Send the response to your server for verification, and
// authenticate the user if the response is valid.
await verifyAutoFillResponse(webAuthnResponse);
} catch (err) {
console.error('Error with conditional UI:', err);
}
}
}
})();
</script>
上記の場合、次のことが発生します。
- サーバーから認証オプションを取得します。 少なくともランダムな
challenge
を返し、この認証要求に関連付けるrpId
を返します。 - ユーザーが username フィールドと対話すると、ブラウザーとプラットフォームは、証明書利用者と共に使用できるパスキーが (プラットフォーム認証システムに) 存在するかどうかを確認します。
- その 場合 パスキーは、選択するオプションとしてユーザーに表示されます (ブラウザーのパスワード マネージャーに格納されているユーザー名など、自動入力できるその他の資格情報と共に)。 ブラウザー/プラットフォームは、次に示すような UI をレンダリングする場合があります。 ただし、正確な外観は、プラットフォームやフォーム ファクターによって異なります。
- ユーザーがパスキーを選択した場合、プラットフォーム UI はユーザーに (多くの場合、生体認証ベースの) ユーザー検証チェックを案内します。
- ユーザーがユーザー検証に成功した場合、
navigator.credentials.get()
呼び出しは成功し、WebAuthn 応答を返します。 - ユーザーがパスキー以外の資格情報を選択した場合、ブラウザー/プラットフォームは別の適切なアクション (ユーザー名の自動入力など) を選択し、
navigator.credentials.get()
呼び出しは解決されません。 - ユーザーが [Passkey from another device]\(別のデバイスからのパスキー\) オプションを選択した場合 (正確なテキストはプラットフォームによって若干異なります)、ブラウザー/プラットフォームは、FIDO2 セキュリティ キーまたはクロスデバイス認証 (CDA) フローを使用して、スマートフォンまたはタブレットからのパスキーを使用して、
navigator.credentials.get()
呼び出しに WebAuthn 応答を配信するようにユーザーに案内します。 - 検証と追加のセキュリティ チェックのために、WebAuthn 応答をサーバーに送信します。 すべてのチェックが成功した場合は、このユーザーの認証済みセッションを開始します。
これが、webAuthn の conditional UI (またはより一般的には、 オートフィル UI) モードと呼ばれる理由です。ユーザーが検証を行うか、電話を使用してユーザーを誘導するプラットフォーム認証 UI は、ユーザーがこのデバイスにパスキーを持っている場合 (または "別のデバイス" オプションを選択した場合) にのみ表示されます。
ご覧のとおり、このモードでは、 navigator.credentials.get()
呼び出しは成功するか、解決されないためではありません。 成功した場合、呼び出しの結果、ユーザー ID と署名された WebAuthn アサーションの両方が表示されます。このアサーションは、証明書利用者 (RP) がユーザーの認証に使用します。
呼び出しが成功しない場合は、 legacy ユーザー認証を実行する必要があります。 この最初のページからユーザー名を取得し、以降のページでは、適切なログイン チャレンジ (パスワード、SMS チャレンジへの応答など) をユーザーに提供します。 これには、 アカウントの回復 ユーザーが自分のパスワードを忘れた場合や、通常のログイン チャレンジに合格できない場合の手順が含まれる場合があります。 ユーザーがすべてのログイン チャレンジに合格すると、認証されてサインインされたと見なされます。
ユーザーが証明書利用者 (RP) のアカウントをまだ持っていない場合は、通常、サインイン ページでアカウントを作成するオプションをユーザーに提供します。 ユーザーがそのオプションを選択した場合は、新しいアカウントを開くために必要な情報をユーザーから収集します。 新しいアカウントを正常に開くと、認証されてサインインされたと見なされます。
ユーザーがサインインしたら、新しいパスキーを設定する必要があります。 これは、次のいずれかの場合に行います。
- ユーザーは、パスキー以外のログイン チャレンジ (パスワードの使用など) を渡すことによって、デバイス上のアカウントをブートストラップしました。
- ユーザーは証明書利用者 (RP) で新しいアカウントを作成したばかりで、そのためサインインと見なされます。
- ユーザーはパスキーを使用していましたが、現在使用しているデバイスとは異なるデバイスを使用していました (上の例で示した "別のデバイス" を選択します)。 これは、返された PublicKeyCredential オブジェクトの authenticatorAttachment 属性を調べることで確認できます。
1.2: クロスデバイス認証
ユーザーが別のデバイス (電話、タブレット、FIDO2 セキュリティ キーなど) のパスキーを使用した場合、認証応答の authenticatorAttachment プロパティ (getAssertion) には値が cross-platform
。
そのシナリオでは、ローカル デバイスでパスキーを作成する選択肢をユーザーに提供します。 ユーザーは他のデバイスを使用する必要がないため、将来、よりシームレスなユーザー エクスペリエンスが得られます。
1.3: ユーザーの確認に関する注意事項
このガイダンスでは、 userVerification を preferred
に設定します。つまり、可能な場合はユーザー検証が試行されます。
デスクトップ コンピューターや古いノート PC などの一部のデバイスには、生体認証センサーがない場合があります。 これらのデバイスで、 userVerification が required
に設定されている場合、ユーザーはパスキーを使用してサインインするたびにシステム ログイン パスワードの入力を求められる場合があります。 そして、それは彼らにとって不満になる可能性があります。
preferred
を使用する場合、一部のプラットフォーム認証子は、デバイスに生体認証センサーがある場合は常にユーザー検証チェックを必要としますが、デバイスがない場合はユーザー検証をスキップする可能性があります。
ユーザー検証の結果 (認証データ フラグで伝達) は、実際のユーザー検証結果を反映し、常にサーバー上の要件に照らして検証する必要があります。
1.4: passkeys にユーザーをオプトインする
まず、多要素認証を含む他のログイン方法を使用して、ユーザーが十分に強力に認証されていることを確認します。
次に、ユーザーのデバイスとオペレーティング システム (OS) のコンボが、次を呼び出してパスキーをサポートしていることを確認します。
PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable()
パスキーがサポートされている場合は、 true
が返されます。 サポートされていない場合は、 false
が返され、パスキー登録フローを中止する必要があります。
パスキーの作成を提供するユーザーにオプトインまたは "アップセル" モーダル/スポットまたはページを提供します。
ヒント
ユーザーが十分な情報に基づいた同意を得られるようにするには、現在のデバイスのロックを解除できるすべてのユーザーが証明書利用者 (RP) のアカウントにアクセスできることを説明する長い説明を表示 (またはリンク) することを検討してください。
ユーザーが同意した場合は、次の例に示すオプションを使用して navigator.credentials.create()
を呼び出します。
navigator.credentials.create({
publicKey: {
rp: {
// User-friendly name of your service.
name: "Passkeys Developer",
// Relying party (RP) identifier (hostname/FQDN).
id: passkeys.contoso"
},
user: {
// Persistent, unique identifier for the user account in your backend.
id: Uint8Array.from("0525bc79-5a63-4e47-b7d1-597e25f5caba", c => c.charCodeAt(0)),
// User-friendly identifier often displayed to the user (for example, email address).
name: "amanda@contoso.com",
// Human-readable display name, sometimes displayed by the client.
displayName: "Amanda Brady"
},
// The challenge is a buffer of cryptographically random bytes generated on your backend,
// and should be tightly bound to the current user session.
challenge: Uint8Array.from("XZJscsUqtBH7ZB90t2g0EbZTZYlbSRK6lq7zlN2lJKuoYMnp7Qo2OLzD7xawL3s", c => c.charCodeAt(0)),
pubKeyCredParams: [
// An array of objects describing what public key types are acceptable to a server.
{
"type": "public-key",
"alg": -7 // EC P256
},
{
"type": "public-key",
"alg": -257 // RSA
}
],
excludeCredentials: [
// Array of credential IDs for existing passkeys tied to the user account.
// This avoids creating a new passkey in an authenticator that already has
// a passkey tied to the user account.
{
// Example only.
type: "public-key",
id: new Uint8Array([21, 31, 56, ...]).buffer
},
{
// Example only.
type: "public-key",
id: new Uint8Array([21, 31, 56, ...]).buffer
}
],
authenticatorSelection: {
// Tells the authenticator to create a passkey.
residentKey: "required",
// Tells the client/authenticator to request user verification where possible;
// for example, a biometric or a device PIN.
userVerification: "preferred"
},
"extensions": {
// Returns details about the passkey.
"credProps": true
}
}
})
Note
ほとんどの証明書利用者 (RP) は、構成証明伝達パラメーター attestation
(既定では none) を指定せず、代わりに値 indirect
を明示的に使用することをお勧めします。 これにより、最も合理化されたユーザー エクスペリエンスが保証されます (プラットフォームは、他の種類の構成証明伝達についてユーザーから同意を得る可能性が高く、ユーザーが作成をキャンセルしたために資格情報の作成が失敗する可能性が高くなります)。
WebAuthn 呼び出しが解決したら、サーバーに応答を送信し、返された公開キーと資格情報 ID を以前に認証されたユーザー アカウントに関連付けます。
ユース ケース 2: 再認証
再認証にパスキーを使用することは、次のいずれかの理由で必要になる場合があります。
- ユーザーがサインアウトし、もう一度サインインする必要があります。
- 非アクティブのためユーザー セッションの有効期限が切れ、ユーザーはもう一度サインインしたいと考えています。
- ユーザーは機密性の高いアクションを実行しようとしているので、ユーザー セッションの制御を再度確認する必要があります。
これらの各状況でユーザーを再認証するには、前のユース ケースで設定したパスキーを使用します。 WebAuthn API 呼び出しは 3 つのケースすべてで同じですが、提供する UI 処理は若干異なります。 特定のアカウントはユーザーによって指定されているため、プラットフォームは、サービス上の別のアカウントを選択するようにユーザーに求めるメッセージを表示しません。
2.1: 機密性の高いアクション
まず、3 番目の理由で UI を見てみましょう。機密性の高いアクションを再認証する場合は、ユーザーに少なくとも 1 つのパスキーの資格情報 ID があるかどうかを確認します。
そのような資格情報 ID が使用できない場合は、再認証に適した従来のログイン チャレンジを提供します。次に例を示します。
ヒント
このログイン チャレンジ ページでは、ユーザーが自分のアカウント識別子を変更できないことをお勧めします。 また、ログイン チャレンジは、デバイスの承認されていないユーザーが合格できないことにする必要があります。
一方、ユーザーのパスキー資格情報 ID が少なくとも 1 つ見つかる場合は、再認証にパスキーを使用できます。
ユーザーの準備ができたら (上記の例では、[移動] ボタンをクリックしたときに)、 navigator.credentials.get()
を呼び出し、ユーザーのすべてのパスキー資格情報 ID を渡します。
navigator.credentials.get({
publicKey: {
challenge: ...,
rpId: ...,
allowCredentials: [{
type: "public-key",
id: new UInt8Array([21, 31, 56, ...]).buffer,
}, {
type: "public-key",
id: new UInt8Array([21, 31, 56, ...]).buffer,
}, {
...
}],
// see note below
userVerification: "preferred",
}
});
Note
前のユース ケースの userVerification に関するガイダンスを必ずお読みください。
ユーザーが代わりに [別の方法で試す] をクリックした場合は、他のサインイン方法 (パスワードなど) を提供して再認証する必要があります (ユーザーが他のサインイン方法を使用できるものとします)。
2.2: 期限切れのセッションとログアウト
次に、ユーザーが自分自身をログアウトしたか、証明書利用者 (RP) がユーザーのセッションの有効期限が切れたために再認証がトリガーされるケースを調べます。 これを容易にするには、RP は、ユーザーがサインアウトしたと見なした場合でも (Cookie やローカル ストレージなどのブラウザー成果物を使用して実現できる) 以前にサインインしていたアカウントを思い出させる何らかの形式のユーザー セッション状態を保持する必要があります。
Note
証明書利用者 (RP) は、サインアウトを包括的なアクションとして扱うことを選択し、ユーザーの ID へのすべての参照を削除する場合があります。 このような RP では、以降のサインインをアカウント ブートストラップのように処理し、前に説明した手順を繰り返す必要があります。
RP として、次のようなサインイン ページを提供できます。
ユーザーが [別のアカウントを使用する] をクリックした場合は、前のユース ケースで説明したように、アカウント ブートストラップ フローを入力する必要があります。ここで手順を繰り返します。ここで、プラットフォームでは、使用するアカウントをユーザーが選択できます。
Note
その場合は、サインイン ページに表示されないように、推奨されるアカウントを完全に削除する機能もユーザーに付与する必要があります。
ただし、ユーザーが [サインイン] ボタンをクリックした場合は、少なくとも 1 つのパスキー資格情報 ID がユーザーに関連付けられているかどうかを確認します。 使用できる資格情報 ID がない場合は、再認証に適した従来のログイン チャレンジを提供します。次に例を示します。
一方、ユーザーのパスキー資格情報 ID が少なくとも 1 つ見つかる場合は、再認証にパスキーを使用できます。
ユーザーの準備ができたら (上記の例では、"Go" ボタンをクリックしたときに)、既に示されているとおりに (つまり、すべてのユーザーのパスキー資格情報 ID を渡すことによって) navigator.credentials.get()
を呼び出します。
ユーザーが代わりに [別の方法で試す] をクリックした場合は、他のサインイン方法 (パスワードなど) を提供して再認証する必要があります (ユーザーが他のサインイン方法を使用できるものとします)。
次のステップ
次に、パスキーの Tools とライブラリを参照してください。
詳細情報
- パスキーの概要
- Passkeys.dev
- FIDO Alliance の Web サイトで パスワードレス体験を開始する
Windows developer