高度なユーザー エクスペリエンスを提供するには、ユーザーがウェブサイトで本人確認を行えるようにすることが重要です。認証されたユーザーは、専用のプロファイルを使用して相互にやり取りしたり、デバイス間でデータを同期したり、オフラインでデータを処理したりできます。ただし、パスワードの作成、記憶、入力は、特にモバイル画面ではエンドユーザーにとって煩雑になりがちで、異なるサイトで同じパスワードを再利用することになります。これはもちろんセキュリティ リスクです。
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 からアカウントを選択できます。
パスワード認証情報オブジェクトの取得
パスワード認証情報をアカウントのオプションとして表示するには、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 プロバイダの配列を受け取る federated
を get()
オプションに追加します。
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
プロパティを調べて、PasswordCredential
(type == 'password'
)か FederatedCredential
(type == '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
});
ユーザーが自動的に再ログインできるようにする
ユーザーがウェブサイトを離れてから後で戻ってきた場合、セッションが期限切れになっている可能性があります。ユーザーがアクセスするたびにパスワードを入力してもらう必要はありません。ユーザーが自動的に再ログインできるようにします。
認証情報オブジェクトの取得
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: true
と navigator.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 について詳しくは、統合ガイドをご覧ください。