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

高度なユーザー エクスペリエンスを提供するには、ユーザーがウェブサイトで本人確認を行えるようにすることが重要です。認証されたユーザーは、専用のプロファイルを使用して相互にやり取りしたり、デバイス間でデータを同期したり、オフラインでデータを処理したりできます。ただし、パスワードの作成、記憶、入力は、特にモバイル画面ではエンドユーザーにとって煩雑になりがちで、異なるサイトで同じパスワードを再利用することになります。これはもちろんセキュリティ リスクです。

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

認証情報管理 API とは何ですか?

Credential Management API を使用すると、デベロッパーはパスワード認証情報と連携認証情報を保存および取得できます。この API には次の 3 つの関数があります。

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

デベロッパーは、これらのシンプルな API を使用して、次のような強力な処理を行うことができます。

  • ユーザーがワンタップだけでログインできるようにします。
  • ユーザーがログインに使用した連携アカウントを記憶します。
  • セッションが期限切れになったときにユーザーを再度ログインさせる。

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

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

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

すべてのケースを網羅することはほぼ不可能ですが、一般的なシングルページ アプリについて見てみましょう。

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

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

  • ログイン時にアカウント選択ツールを表示: ユーザーが [ログイン] をタップすると、ネイティブのアカウント選択ツール 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
    ...

認証情報オブジェクトの 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() を使用して、保存する認証情報オブジェクトを作成します。

Chrome が、認証情報(またはフェデレーション プロバイダ)を保存するかどうかをユーザーに尋ねます。
認証情報(またはフェデレーション プロバイダ)を保存するかどうかをユーザーに確認するメッセージが Chrome に表示されます

フォーム要素からパスワード認証情報を作成して保存する

次のコードでは、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
});
ログインフロー図。

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

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

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

認証情報オブジェクトの取得

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
    ...
    }
});

コードは、[ログイン時にアカウント選択ツールを表示する] セクションで説明したコードと類似しています。唯一の違いは、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 の詳細については、統合ガイドをご覧ください。