認証情報管理 API の最新情報

ここで説明する更新の一部は、Google I/O セッション「セキュアでシームレスなログイン: ユーザー エンゲージメントの維持」で説明されています。

Chrome 57

Chrome 57 では、Credential Management API にこの重要な変更が導入されました。

別のサブドメインから認証情報を共有できます

Chrome で Credential Management API を使用して、別のサブドメインに保存されている認証情報を取得できるようになりました。たとえば、パスワードが login.example.com に保存されている場合、www.example.com のスクリプトは、Account Chooser ダイアログでアカウント アイテムの 1 つとしてパスワードを表示できます。

navigator.credentials.store() を使用してパスワードを明示的に保存する必要があります。これにより、ユーザーがダイアログをタップして認証情報を選択すると、パスワードが現在のオリジンに渡され、コピーされます。

パスワードが保存されると、www.example.com 以降はまったく同じオリジンで認証情報として使用できるようになります。

次のスクリーンショットでは、login.aliexpress.com に保存されている認証情報情報が m.aliexpress.com に表示され、ユーザーが選択できるようになっています。

選択したサブドメインのログイン情報が表示されているアカウント選択ツール

Chrome 60

Chrome 60 では、Credential Management API に重要な変更がいくつかあります。

特徴検出について確認が必要です

パスワード ベースの認証情報や連携認証情報にアクセスするための Credential Management API が使用可能かどうかを確認するには、window.PasswordCredential または window.FederatedCredential が使用可能かどうかを確認します。

if (window.PasswordCredential || window.FederatedCredential) {
  // The Credential Management API is available
}

PasswordCredential オブジェクトにパスワードが追加されました。

Credential Management API は、パスワードの処理に対して控えめなアプローチを取っていました。これは JavaScript からパスワードを隠蔽するため、デベロッパーは fetch() API の拡張機能を介して検証のために PasswordCredential オブジェクトをサーバーに直接送信する必要があります。

しかし、このアプローチにはいくつかの制限がありました。以下の理由により、この API を使用できないというフィードバックをいただきました。

  • JSON オブジェクトの一部としてパスワードを送信する必要がありました。

  • パスワードのハッシュ値をサーバーに送信する必要がありました。

セキュリティ分析を実施し、パスワードを JavaScript から隠してもすべての攻撃ベクトルを期待したほど効果的に防ぐことはできないと判断し、変更を加えることにしました。

Credential Management API で、返された認証情報オブジェクトに未加工のパスワードが含まれるようになったため、書式なしテキストでアクセスできるようになりました。サーバーに認証情報を配信するには、既存の方法を使用できます。

navigator.credentials.get({
    password: true,
    federated: {
    providers: [ 'https://accounts.google.com' ]
    },
    mediation: 'silent'
}).then(passwordCred => {
    if (passwordCred) {
    let form = new FormData();
    form.append('email', passwordCred.id);
    form.append('password', passwordCred.password);
    form.append('csrf_token', csrf_token);
    return fetch('/signin', {
        method: 'POST',
        credentials: 'include',
        body: form
    });
    } else {

    // Fallback to sign-in form
    }
}).then(res => {
    if (res.status === 200) {
    return res.json();
    } else {
    throw 'Auth failed';
    }
}).then(profile => {
    console.log('Auth succeeded', profile);
});

カスタム取得はまもなくサポート終了となります

カスタム fetch() 関数を使用しているかどうかを判断するには、credentials プロパティの値として PasswordCredential オブジェクトと FederatedCredential オブジェクトのどちらを使用しているかを確認します。次に例を示します。

fetch('/signin', {
    method: 'POST',
    credentials: c
})

前のコードサンプルで示した通常の fetch() 関数を使用するか、XMLHttpRequest を使用することをおすすめします。

Chrome 60 までは、navigator.credentials.get() はブール値のフラグを持つオプションの unmediated プロパティを受け付けていました。次に例を示します。

navigator.credentials.get({
    password: true,
    federated: {
    providers: [ 'https://accounts.google.com' ]
    },
    unmediated: true
}).then(c => {

    // Sign-in
});

unmediated: true を設定すると、認証情報を渡すときにブラウザからアカウント選択ツールが表示されなくなります。

このフラグがメディエーションとして拡張されました。ユーザー メディエーションは、次のような場合に発生します。

  • ユーザーは、ログインに使用するアカウントを選択する必要があります。

  • ユーザーが navigator.credentials.requireUseMediation() 呼び出し後に明示的にログインしたいと考えている。

mediation 値には、次のいずれかのオプションを選択します。

mediation ブール値フラグとの比較 動作
silent unmediated: true と等しい アカウント選択ツールを表示せずに認証情報が渡されました。
optional unmediated: false と等しい preventSilentAccess() が以前に呼び出された場合は、アカウント選択ツールが表示されます。
required 新しいオプション Account Chooser を常に表示する。 ユーザーがネイティブの Account Chooser ダイアログを使用してアカウントを切り替えられるようにする場合に役立ちます。

この例では、前のフラグ unmediated: true に相当するアカウント選択ツールを表示せずに認証情報が渡されます。

navigator.credentials.get({
    password: true,
    federated: {
    providers: [ 'https://accounts.google.com' ]
    },
    mediation: 'silent'
}).then(c => {

    // Sign-in
});

requireUserMediation() の名前を preventSilentAccess() に変更しました

get() 呼び出しで提供される新しい mediation プロパティに合わせて、navigator.credentials.requireUserMediation() メソッドの名前を navigator.credentials.preventSilentAccess() に変更しました。

名前が変更されたメソッドでは、アカウント選択ツールを表示せずに認証情報を渡せなくなります(ユーザー メディエーションなしで呼び出されることもあります)。これは、ユーザーがウェブサイトからログアウトまたは登録解除し、次回アクセスする際に自動的に再ログインすることを希望しない場合に便利です。

signoutUser();
if (navigator.credentials) {
    navigator.credentials.preventSilentAccess();
}

新しいメソッド navigator.credentials.create() を使用して認証情報オブジェクトを非同期で作成する

新しいメソッド navigator.credentials.create() を使用して、認証情報オブジェクトを非同期で作成できるようになりました。同期と非同期の両方の手法について以下で比較します。

PasswordCredential オブジェクトの作成

同期方法
let c = new PasswordCredential(form);
非同期アプローチ(新規)
let c = await navigator.credentials.create({
    password: form
});

または

let c = await navigator.credentials.create({
    password: {
    id: id,
    password: password
    }
});

FederatedCredential オブジェクトの作成

同期方法
let c = new FederatedCredential({
    id:       'agektmr',
    name:     'Eiji Kitamura',
    provider: 'https://accounts.google.com',
    iconURL:  'https://*****'
});
非同期アプローチ(新規)
let c = await navigator.credentials.create({
    federated: {
    id:       'agektmr',
    name:     'Eiji Kitamura',
    provider: 'https://accounts.google.com',
    iconURL:  'https://*****'
    }
});

移行ガイド

Credential Management API がすでに実装されている場合、新しいバージョンへのアップグレードについては、移行ガイドのドキュメントをご覧ください。