認証情報管理 API を使用したログインフローの効率化

洗練されたユーザー エクスペリエンスを提供するには、ウェブサイトでユーザーが自身の認証を行えることが重要です。認証されたユーザーは、専用のプロファイルを使用して相互にやり取りしたり、デバイス間でデータを同期したり、オフライン中にデータを処理したりできます。このリストはさまざまな機能を備えています。しかし、パスワードの作成、記憶、入力は、エンドユーザーにとって面倒になる傾向があり、特にモバイル画面では、異なるサイトで同じパスワードを使い回してしまいます。これは当然 セキュリティリスクです

Chrome の最新バージョン(51)は、Credential Management API をサポートしています。これは W3C の規格追跡案で、デベロッパーがブラウザの認証情報マネージャーにプログラムでアクセスできるようにし、ユーザーがより簡単にログインできるようにしています。

Credential Management API とは何ですか?

Credential Management API を使用すると、デベロッパーはパスワード認証情報とフェデレーション認証情報を保存および取得でき、次の 3 つの機能が提供されます。

  • navigator.credentials.get()
  • navigator.credentials.store()
  • navigator.credentials.requireUserMediation()

これらのシンプルな API を使用することで、デベロッパーは次のような優れた機能を実現できます。

  • ユーザーがワンタップでログインできるようにします。
  • ユーザーがログインに使用した連携アカウントを記憶します。
  • セッションの有効期限が切れたときにユーザーをログインし直す。

Chrome の実装では、認証情報は Chrome のパスワード マネージャーに保存されます。Chrome にログイン済みのユーザーは、デバイス間でユーザーのパスワードを同期できます。同期されたパスワードは、Smart Lock for Passwords API for Android を統合した Android アプリでも共有でき、シームレスなクロス プラットフォーム エクスペリエンスが実現します

Credential Management API をサイトに統合する

ウェブサイトで Credential Management API を使用する方法は、アーキテクチャによって異なります。シングルページ アプリですか。ページ遷移のある以前のアーキテクチャか?ログイン フォームがトップページにのみ表示されているか。ログインボタンはいたるところにありますか?ユーザーがログインせずに有意義に ウェブサイトを閲覧できるかポップアップ ウィンドウ内で連携は機能しますか?それとも複数ページにわたるインタラクションが必要か?

すべてのケースを網羅することはほぼ不可能ですが、典型的な単一ページアプリを見てみましょう。

  • トップページは登録フォームです。
  • ユーザーが [ログイン] ボタンをタップすると、ログイン フォームが表示されます。
  • 登録フォームとログイン フォームのどちらにも、ID/パスワードの認証情報と連携(Google ログインや Facebook ログインなど)の一般的なオプションが用意されています。

Credential Management API を使用すると、次のような機能をサイトに追加できます。

  • ログイン時に Account Chooser を表示する: ユーザーが [ログイン] をタップしたときに、ネイティブのアカウント選択ツールの UI を表示します。
  • 認証情報を保存する: ログインに成功したら、後で使用できるように認証情報をブラウザのパスワード マネージャーに保存することを提案します。
  • ユーザーが自動的に再ログインできるようにする: セッションの有効期限が切れた場合に、ユーザーが再ログインできるようにします。
  • 自動ログインをメディエーションする: ユーザーがログアウトした後、そのユーザーが次回アクセスする際に自動ログインを無効にします。

これらの機能の実装は、デモサイトサンプルコードを使って体験できます。

ログイン時に Account Chooser を表示する

ユーザーが [ログイン] ボタンをタップしてからログイン フォームに移動するまでの間に、navigator.credentials.get() を使用して認証情報を取得できます。Chrome でアカウント選択ツールの UI が表示され、ユーザーはここからアカウントを選択できます。

ログインするアカウントを選択するためのアカウント選択ツールの UI がポップアップ表示される。
ログインするアカウントを選択するためのアカウント選択ツールの UI がポップアップ表示される

パスワード認証情報オブジェクトを取得する

アカウント オプションとしてパスワード認証情報を表示するには、password: true を使用します。

navigator.credentials.get({
    password: true, // `true` to obtain password credentials
}).then(function(cred) {
    // continuation
    ...

パスワード認証情報を使用してログインする

ユーザーがアカウントを選択すると、解決関数がパスワード認証情報を受け取ります。fetch() を使用してサーバーに送信できます。

    // continued from previous example
}).then(function(cred) {
    if (cred) {
    if (cred.type == 'password') {
        // Construct FormData object
        var form = new FormData();

        // Append CSRF Token
        var csrf_token = document.querySelector('csrf_token').value;
        form.append('csrf_token', csrf_token);

        // You can append additional credential data to `.additionalData`
        cred.additionalData = form;

        // `POST` the credential object as `credentials`.
        // id, password and the additional data will be encoded and
        // sent to the url as the HTTP body.
        fetch(url, {           // Make sure the URL is HTTPS
        method: 'POST',      // Use POST
        credentials: cred    // Add the password credential object
        }).then(function() {
        // continuation
        });
    } else if (cred.type == 'federated') {
        // continuation

連携認証情報を使用したログイン

フェデレーション アカウントを表示するには、ID プロバイダの配列を受け取る federatedget() オプションに追加します。

複数のアカウントがパスワード マネージャーに保存されている場合。
パスワード マネージャーに複数のアカウントを保存している場合
navigator.credentials.get({
    password: true, // `true` to obtain password credentials
    federated: {
    providers: [  // Specify an array of IdP strings
        'https://accounts.google.com',
        'https://www.facebook.com'
    ]
    }
}).then(function(cred) {
    // continuation
    ...

credential オブジェクトの type プロパティを調べて、それが PasswordCredentialtype == 'password')と FederatedCredentialtype == 'federated')のどちらであるかを確認できます。認証情報が FederatedCredential の場合は、そこに含まれる情報を使用して適切な API を呼び出すことができます。

    });
} else if (cred.type == 'federated') {
    // `provider` contains the identity provider string
    switch (cred.provider) {
    case 'https://accounts.google.com':
        // Federated login using Google Sign-In
        var auth2 = gapi.auth2.getAuthInstance();

        // In Google Sign-In library, you can specify an account.
        // Attempt to sign in with by using `login_hint`.
        return auth2.signIn({
        login_hint: cred.id || ''
        }).then(function(profile) {
        // continuation
        });
        break;

    case 'https://www.facebook.com':
        // Federated login using Facebook Login
        // continuation
        break;

    default:
        // show form
        break;
    }
}
// if the credential is `undefined`
} else {
// show form
認証情報管理のフローチャート

認証情報を保存する

ユーザーがフォームを使用してウェブサイトにログインしたら、navigator.credentials.store() を使用して認証情報を保存します。保存するかどうかを尋ねるメッセージがユーザーに表示されます。認証情報の種類に応じて、new PasswordCredential() または new FederatedCredential() を使用して、保存する認証情報オブジェクトを作成します。

認証情報(またはフェデレーション プロバイダ)を保存するかどうかをユーザーに確認します。
認証情報(または連携プロバイダ)を保存するかどうかをユーザーに尋ねる

フォーム要素からのパスワード認証情報の作成と保存

次のコードは、autocomplete 属性を使用して、フォームの要素を PasswordCredential オブジェクトのパラメータに自動的にマッピングします。

HTML html <form id="form" method="post"> <input type="text" name="id" autocomplete="username" /> <input type="password" name="password" autocomplete="current-password" /> <input type="hidden" name="csrf_token" value="******" /> </form>

JavaScript

var form = document.querySelector('\#form');
var cred = new PasswordCredential(form);
// Store it
navigator.credentials.store(cred)
.then(function() {
    // continuation
});

連携認証情報の作成と保存

// After a federation, create a FederatedCredential object using
// information you have obtained
var cred = new FederatedCredential({
    id: id,                                  // The id for the user
    name: name,                              // Optional user name
    provider: 'https://accounts.google.com',  // A string that represents the identity provider
    iconURL: iconUrl                         // Optional user avatar image url
});
// Store it
navigator.credentials.store(cred)
.then(function() {
    // continuation
});
ログインフローの図。

ユーザーが自動的に再ログインできるようにする

ユーザーがウェブサイトを離れて、後で再びアクセスしたときに、セッションの有効期限が切れている可能性があります。ユーザーが戻ってくるたびにパスワードを入力する必要はありません。ユーザーが自動的に再ログインできるようにします。

ユーザーが自動的にログインすると、通知がポップアップ表示されます。
ユーザーが自動的にログインすると、通知がポップアップ表示されます。

credential オブジェクトの取得

navigator.credentials.get({
    password: true, // Obtain password credentials or not
    federated: {    // Obtain federation credentials or not
    providers: [  // Specify an array of IdP strings
        'https://accounts.google.com',
        'https://www.facebook.com'
    ]
    },
    unmediated: true // `unmediated: true` lets the user automatically sign in
}).then(function(cred) {
    if (cred) {
    // auto sign-in possible
    ...
    } else {
    // auto sign-in not possible
    ...
    }
});

コードは、「ログイン時に Account Chooser を表示する」セクションで説明したような内容になっています。唯一の違いは、unmediated: true を設定することです。

これにより、関数が直ちに解決され、ユーザーを自動的にログインさせるための認証情報が提供されます。次のような条件があります。

  • ユーザーがウェルカム メッセージで自動ログイン機能を承認しました。
  • ユーザーが以前に Credential Management API を使用してウェブサイトにログインした。
  • オリジンの認証情報が 1 つだけ保存されている。
  • ユーザーが前回のセッションで明示的にログアウトしなかった。

これらの条件のいずれかが満たされない場合、関数は拒否されます。

認証情報オブジェクトのフロー図

自動ログインをメディエーションする

ユーザーがウェブサイトからログアウトした場合、そのユーザーが自動的に再ログインしないようにするのは、デベロッパー側の責任です。これを実現するため、Credential Management API にはメディエーションというメカニズムが用意されています。メディエーション モードを有効にするには、navigator.credentials.requireUserMediation() を呼び出します。オリジンでユーザーのメディエーション ステータスが有効になっている限り、unmediated: truenavigator.credentials.get() とともに使用すると、その関数は undefined で解決されます。

自動ログインのメディエーション

navigator.credentials.requireUserMediation();
自動ログインのフローチャート

よくある質問

ウェブサイトの JavaScript で未加工のパスワードを取得することは可能ですか?いいえ。パスワードは PasswordCredential の一部としてのみ取得でき、いかなる方法でも公開することはできません。

Credential Management API を使用して、ID に 3 桁の数字を保存することはできますか?現時点では受け付けていません。仕様に関するフィードバックをお寄せください。

iframe 内で Credential Management API を使用できますか?API はトップレベル コンテキストに限定されています。iframe 内で .get() または .store() を呼び出すと、すぐに解決されてしまいます。

パスワード管理用の Chrome 拡張機能を Credential Management API と統合できますか? navigator.credentials をオーバーライドして Chrome 拡張機能にフックすると、get() または store() の認証情報を取得できます。

リソース

Credential Management API について詳しくは、統合ガイドをご覧ください。