検出可能な認証情報の詳細

パスキーなどの FIDO 認証情報はパスワードの置き換えを目的としていますが、ほとんどの認証情報ではユーザーがユーザー名を入力する必要もなくなります。これにより、ユーザーは現在のウェブサイトのパスキーのリストからアカウントを選択して認証できるようになります。

以前のバージョンのセキュリティ キーは 2 段階認証プロセスの認証方法として設計されており、認証情報の ID が必要だったため、ユーザー名の入力が必要でした。ID を知らなくてもセキュリティ キーで検出できる認証情報は、検出可能な認証情報と呼ばれます。現在作成されている FIDO 認証情報のほとんどは検出可能な認証情報です。特に、パスワード マネージャーまたは最新のセキュリティ キーに保存されているパスキーが該当します。

認証情報がパスキー(検出可能な認証情報)として作成されるようにするには、認証情報の作成時に residentKeyrequireResidentKey を指定します。

RP は、パスキー認証時に allowCredentials を省略することで、検出可能な認証情報を使用できます。この場合、ブラウザまたはシステムは、作成時に設定された user.name プロパティで識別される、利用可能なパスキーのリストをユーザーに表示します。ユーザーが 1 つ選択すると、user.id 値が結果のシグネチャに含まれます。サーバーは、入力されたユーザー名の代わりに、その値または返された認証情報 ID を使用してアカウントを検索できます。

前述のアカウント セレクタ UI では、検出できない認証情報が表示されることはありません。

requireResidentKeyresidentKey

パスキーを作成するには、navigator.credentials.create()authenticatorSelection.residentKeyauthenticatorSelection.requireResidentKey を次のように指定します。

async function register () {
  // ...

  const publicKeyCredentialCreationOptions = {
    // ...
    authenticatorSelection: {
      authenticatorAttachment: 'platform',
      residentKey: 'required',
      requireResidentKey: true,
    }
  };

  const credential = await navigator.credentials.create({
    publicKey: publicKeyCredentialCreationOptions
  });

  // This does not run until the user selects a passkey.
  const credential = {};
  credential.id = cred.id;
  credential.rawId = cred.id; // Pass a Base64URL encoded ID string.
  credential.type = cred.type;

  // ...
}

residentKey:

  • 'required': 検出可能な認証情報を作成する必要があります。作成できない場合は、NotSupportedError が返されます。
  • 'preferred': RP は検出可能な認証情報の作成を優先しますが、非検出可能な認証情報も受け入れます。
  • 'discouraged': RP は検出不可能な認証情報の作成を優先しますが、検出可能な認証情報も受け入れます。

requireResidentKey:

  • このプロパティは、古いバージョンの仕様である WebAuthn Level 1 からの下位互換性を維持するために保持されています。residentKey'required' の場合は true に設定し、それ以外の場合は false に設定します。

allowCredentials

RP は navigator.credentials.get()allowCredentials を使用して、パスキー認証のエクスペリエンスを制御できます。通常、パスキー認証には次の 3 種類があります。

検出可能な認証情報を使用すると、RP はモーダル アカウント セレクタを表示して、ユーザーがログインに使用するアカウントを選択できるようにし、その後でユーザーの確認を行います。これは、パスキー認証専用のボタンを押して開始されるパスキー認証フローに適しています。

このユーザー エクスペリエンスを実現するには、navigator.credentials.get()allowCredentials パラメータを省略するか、空の配列を渡します。

async function authenticate() {
  // ...

  const publicKeyCredentialRequestOptions = {
    // Server generated challenge:
    challenge: ****,
    // The same RP ID as used during registration:
    rpId: 'example.com',
    // You can omit `allowCredentials` as well:
    allowCredentials: []
  };

  const credential = await navigator.credentials.get({
    publicKey: publicKeyCredentialRequestOptions,
    signal: abortController.signal
  });

  // This does not run until the user selects a passkey.
  const credential = {};
  credential.id = cred.id;
  credential.rawId = cred.id; // Pass a Base64URL encoded ID string.
  credential.type = cred.type;
  
  // ...
}

パスキーのフォームの自動入力を表示する

上記のモーダル アカウント セレクタは、ほとんどのユーザーがパスキーを使用し、ローカル デバイスでパスキーを利用できる場合に有効です。ローカル パスキーがないユーザーの場合でも、モーダル ダイアログが表示され、別のデバイスからパスキーを提示するようユーザーに求められます。ユーザーをパスキーに移行する間、パスキーを設定していないユーザーにはこの UI を表示しないようにしたい場合があります。

代わりに、パスキーの選択は、保存済みのユーザー名やパスワードとともに、従来のログイン フォームのフィールドの自動入力プロンプトに組み込まれる可能性があります。これにより、パスキーを使用するユーザーはパスキーを選択してログイン フォームを「入力」でき、ユーザー名とパスワードのペアを保存しているユーザーはそれらを選択でき、どちらも使用していないユーザーはユーザー名とパスワードを入力できます。

このユーザー エクスペリエンスは、RP がパスワードとパスキーを混在して使用する移行中の場合に最適です。

このユーザー エクスペリエンスを実現するには、allowCredentials プロパティに空の配列を渡すか、パラメータを省略するだけでなく、navigator.credentials.get()mediation: 'conditional' を指定し、HTML の username 入力フィールドに autocomplete="username webauthn" を、password 入力フィールドに autocomplete="password webauthn" をアノテーションします。

navigator.credentials.get() の呼び出しによって UI が表示されることはありませんが、ユーザーがアノテーション付きの入力フィールドにフォーカスすると、利用可能なパスキーが自動入力オプションに含まれます。ユーザーが 1 つを選択すると、通常のデバイスのロック解除確認が行われ、その後でのみ .get() から返された Promise が結果とともに解決されます。ユーザーがパスキーを選択しない場合、Promise は解決されません。

async function authenticate() {
  // ...

  const publicKeyCredentialRequestOptions = {
    // Server generated challenge:
    challenge: ****,
    // The same RP ID as used during registration:
    rpId: 'example.com',
    // You can omit `allowCredentials` as well:
    allowCredentials: []
  };

  const cred = await navigator.credentials.get({
    publicKey: publicKeyCredentialRequestOptions,
    signal: abortController.signal,
    // Specify 'conditional' to activate conditional UI
    mediation: 'conditional'
  });

  // This does not run until the user selects a passkey.
  const credential = {};
  credential.id = cred.id;
  credential.rawId = cred.id; // Pass a Base64URL encoded ID string.
  credential.type = cred.type;
  
  // ...
}
<input type="text" name="username" autocomplete="username webauthn" ...>

このユーザー エクスペリエンスの構築方法については、フォームの自動入力でパスキーを使用してログインすると、ウェブアプリでフォームの自動入力を使用してパスキーを実装するの Codelab をご覧ください。

再認証

パスキーを再認証に使用する場合など、ユーザーの識別子がすでにわかっている場合もあります。この場合、ブラウザや OS でアカウント選択画面が表示されないようにして、パスキーを使用したいと考えています。これは、allowCredentials パラメータで認証情報 ID のリストを渡すことで実現できます。

この場合、名前付き認証情報のいずれかがローカルで利用可能な場合、ユーザーはすぐにデバイスのロック解除を求められます。そうでない場合は、有効な認証情報を保持している別のデバイス(スマートフォンまたはセキュリティ キー)を提示するよう求められます。

このユーザー エクスペリエンスを実現するには、ログイン ユーザーの認証情報 ID のリストを提供します。ユーザーはすでに認識されているため、RP はそれらをクエリできる必要があります。navigator.credentials.get()allowCredentials プロパティで、認証情報 ID を PublicKeyCredentialDescriptor オブジェクトとして指定します。

async function authenticate() {
  // ...

  const publicKeyCredentialRequestOptions = {
    // Server generated challenge:
    challenge: ****,
    // The same RP ID as used during registration:
    rpId: 'example.com',
    // Provide a list of PublicKeyCredentialDescriptors:
    allowCredentials: [{
      id: ****,
      type: 'public-key',
      transports: [
        'internal',
        'hybrid'
      ]
    }, {
      id: ****,
      type: 'public-key',
      transports: [
        'internal',
        'hybrid'
      ]
    }, ...]
  };

  const credential = await navigator.credentials.get({
    publicKey: publicKeyCredentialRequestOptions,
    signal: abortController.signal
  });

  // This does not run until the user selects a passkey.
  const credential = {};
  credential.id = cred.id;
  credential.rawId = cred.id; // Pass a Base64URL encoded ID string.
  credential.type = cred.type;
  
  // ...
}

PublicKeyCredentialDescriptor オブジェクトは次の要素で構成されます。

  • id: パスキー登録時に RP が取得した公開鍵認証情報の ID。
  • type: 通常、このフィールドは 'public-key' です。
  • transports: この認証情報を保持するデバイスでサポートされているトランスポートのヒント。ブラウザが、外部デバイスの提示をユーザーに求める UI を最適化するために使用します。このリストを指定する場合、リストには、各認証情報の登録時に getTransports() 関数を呼び出した結果が含まれている必要があります。

概要

検出可能な認証情報を使用すると、ユーザーはユーザー名の入力をスキップできるため、パスキー ログイン エクスペリエンスが大幅に向上します。residentKeyrequireResidentKeyallowCredentials を組み合わせることで、RP は次のようなログイン エクスペリエンスを実現できます。

  • モーダル アカウント セレクタを表示します。
  • パスキーのフォームの自動入力を表示します。
  • 再認証。

検出可能な認証情報を賢く使用します。そうすることで、ユーザーがシームレスに利用でき、エンゲージメントを高めることができる洗練されたパスキー ログイン エクスペリエンスを設計できます。