FedCM を使用してプライバシー保護 ID 連携を行う方法について説明します。
FedCM(Federated Credential Management)は、フェデレーション ID サービス(「... でログイン」など)に対するプライバシー保護のアプローチであり、ユーザーは ID サービスやサイトと個人情報を共有せずにサイトにログインできます。
FedCM のユースケース、ユーザーフロー、API ロードマップについて詳しくは、FedCM API の概要をご覧ください。
FedCM 開発環境
FedCM を使用するには、Chrome の IdP と RP の両方に安全なコンテキスト(HTTPS または localhost)が必要です。
Android の Chrome でコードをデバッグする
FedCM コードをデバッグするために、サーバーをローカルでセットアップして実行します。USB ケーブルでポート転送機能を介して接続された Android デバイス上の Chrome で、このサーバーにアクセスできます。
パソコンで DevTools を使用して Android で Chrome をデバッグできます。手順については、Android デバイスのリモート デバッグをご覧ください。
Chrome でサードパーティ Cookie をブロックする
Chrome でサードパーティ Cookie なしで FedCM がどのように動作するかを、実際に適用する前にテストできます。
サードパーティの Cookie をブロックするには、シークレット モードを使用するか、chrome://settings/cookies
でパソコンの設定(chrome://settings/cookies
)またはモバイルで [設定] > [サイトの設定] > [Cookie] に移動して [サードパーティ Cookie をブロックする] を選択します。
FedCM API の使用
FedCM と統合するには、well-known ファイル、アカウント リストの構成ファイルとエンドポイント、アサーション発行、必要に応じてクライアント メタデータを作成します。
その後、FedCM は RP が IdP でログインするために使用できる JavaScript API を公開します。
well-known ファイルを作成する
トラッカーによる API の悪用を防ぐには、IdP の eTLD+1 の /.well-known/web-identity
から well-known ファイルを提供する必要があります。
たとえば、IdP エンドポイントが https://accounts.idp.example/
で提供される場合、https://idp.example/.well-known/web-identity
の well-known ファイルと IdP 構成ファイルを提供する必要があります。よく知られているファイルの内容の例を次に示します。
{
"provider_urls": ["https://accounts.idp.example/config.json"]
}
JSON ファイルには、RP によって navigator.credentials.get
内の configURL
のパス部分として指定できる IdP 構成ファイルの URL の配列を含む provider_urls
プロパティを含める必要があります。配列内の URL 文字列の数は 1 つに制限されていますが、今後フィードバックによって変更される可能性があります。
IdP 構成ファイルとエンドポイントを作成する
IdP 構成ファイルには、ブラウザに必要なエンドポイントのリストが含まれています。IdP はこの構成ファイルと必要なエンドポイントおよび URL をホストします。すべての JSON レスポンスは application/json
コンテンツ タイプで提供する必要があります。
構成ファイルの URL は、RP で実行される navigator.credentials.get
呼び出しに提供される値によって決まります。
const credential = await navigator.credentials.get({
identity: {
context: 'signup',
providers: [{
configURL: 'https://accounts.idp.example/config.json',
clientId: '********',
nonce: '******'
}]
}
});
const { token } = credential;
IdP 構成ファイルの場所の完全な URL を configURL
として指定します。RP で navigator.credentials.get()
が呼び出されると、ブラウザは Origin
ヘッダーや Referer
ヘッダーなしで GET
リクエストで構成ファイルを取得します。リクエストに Cookie が設定されておらず、リダイレクトも行われていません。これにより、IdP は、リクエストを行ったユーザーと接続しようとしている RP を実質的に学習できなくなります。次に例を示します。
GET /config.json HTTP/1.1
Host: accounts.idp.example
Accept: application/json
Sec-Fetch-Dest: webidentity
ブラウザは、IdP から次のプロパティを含む JSON レスポンスを想定しています。
プロパティ | 説明 |
---|---|
accounts_endpoint (必須) |
アカウント エンドポイントの URL。 |
client_metadata_endpoint (任意) |
クライアント メタデータ エンドポイントの URL。 |
id_assertion_endpoint (必須) |
ID アサーション エンドポイントの URL。 |
disconnect (任意) |
切断エンドポイントの URL。 |
login_url (必須) |
ユーザーが IdP にログインするためのログインページの URL。 |
branding (任意) |
さまざまなブランディング オプションを含むオブジェクト。 |
branding.background_color (任意) |
[次の名前とメールアドレスで続行] ボタンの背景色を設定するブランド オプション。関連する CSS 構文(hex-color 、hsl() 、rgb() 、named-color )を使用します。 |
branding.color (任意) |
[次の名前とメールアドレスで続行] ボタンのテキストの色を設定するブランド オプション。関連する CSS 構文(hex-color 、hsl() 、rgb() 、named-color )を使用します。 |
branding.icons (任意) |
ログイン ダイアログに表示されるアイコン オブジェクトを設定するブランド オプション。アイコン オブジェクトは、次の 2 つのパラメータを持つ配列です。
|
RP は、事前定義された認証コンテキストに対応するため、navigator.credentials.get()
の identity.context
値を介して FedCM ダイアログ UI の文字列を変更できます。オプションのプロパティには、"signin"
(デフォルト)、"signup"
、"use"
、"continue"
のいずれかを指定できます。
IdP からのレスポンス本文の例を次に示します。
{
"accounts_endpoint": "/accounts.php",
"client_metadata_endpoint": "/client_metadata.php",
"id_assertion_endpoint": "/assertion.php",
"disconnect_endpoint": "/disconnect.php",
"login_url": "/login",
"branding": {
"background_color": "green",
"color": "#FFEEAA",
"icons": [{
"url": "https://idp.example/icon.ico",
"size": 25
}]
}
}
ブラウザは構成ファイルを取得すると、後続のリクエストを IdP エンドポイントに送信します。
アカウントのエンドポイント
IdP のアカウント エンドポイントは、ユーザーが現在 IdP でログインしているアカウントのリストを返します。IdP が複数のアカウントをサポートしている場合、このエンドポイントはログインしているすべてのアカウントを返します。
ブラウザが、SameSite=None
を含む Cookie を含む GET
リクエストを送信しますが、client_id
パラメータ、Origin
ヘッダー、または Referer
ヘッダーは含みません。これにより、IdP はユーザーがログインしようとしている RP を実質的に学習できなくなります。次に例を示します。
GET /accounts.php HTTP/1.1
Host: accounts.idp.example
Accept: application/json
Cookie: 0x23223
Sec-Fetch-Dest: webidentity
リクエストを受信すると、サーバーは次の処理を行う必要があります。
- リクエストに
Sec-Fetch-Dest: webidentity
HTTP ヘッダーが含まれていることを確認します。 - セッション Cookie を、すでにログインしているアカウントの ID と照合します。
- アカウントのリストを使用して回答します。
ブラウザは、次のプロパティを含むアカウント情報の配列を含む accounts
プロパティを含む JSON レスポンスを想定しています。
プロパティ | 説明 |
---|---|
id (必須) |
ユーザーの一意の ID。 |
name (必須) |
ユーザーの姓。 |
email (必須) |
ユーザーのメールアドレス。 |
given_name (任意) |
ユーザーの名。 |
picture (任意) |
ユーザーのアバター画像の URL。 |
approved_clients (任意) |
ユーザーが登録した RP クライアント ID の配列。 |
login_hints (任意) |
IdP がアカウントを指定するためにサポートするすべてのフィルタタイプの配列。RP は loginHint プロパティを指定して navigator.credentials.get() を呼び出し、指定されたアカウントを選択的に表示できます。 |
domain_hints (任意) |
アカウントが関連付けられているすべてのドメインの配列。RP は、domainHint プロパティを指定して navigator.credentials.get() を呼び出し、アカウントをフィルタリングできます。 |
レスポンス本文の例:
{
"accounts": [{
"id": "1234",
"given_name": "John",
"name": "John Doe",
"email": "john_doe@idp.example",
"picture": "https://idp.example/profile/123",
"approved_clients": ["123", "456", "789"],
"login_hints": ["demo1", "demo1@idp.example"]
}, {
"id": "5678",
"given_name": "Johnny",
"name": "Johnny",
"email": "johnny@idp.example",
"picture": "https://idp.example/profile/456",
"approved_clients": ["abc", "def", "ghi"],
"login_hints": ["demo2", "demo2@idp.example"],
"domain_hints": ["corp.example"]
}]
}
ユーザーがログインしていない場合は、HTTP 401(Unauthorized)を返します。
返されたアカウント リストはブラウザによって使用され、RP では使用できません。
クライアント メタデータ エンドポイント
IdP のクライアント メタデータ エンドポイントは、RP のプライバシー ポリシーと利用規約などの証明書利用者のメタデータを返します。RP は、プライバシー ポリシーと利用規約へのリンクを事前に IdP に提供する必要があります。ユーザーが IdP にまだ IdP に登録していない場合は、これらのリンクがログイン ダイアログに表示されます。
ブラウザが、Cookie を使用せずに client_id
navigator.credentials.get
を使用して GET
リクエストを送信します。次に例を示します。
GET /client_metadata.php?client_id=1234 HTTP/1.1
Host: accounts.idp.example
Origin: https://rp.example/
Accept: application/json
Sec-Fetch-Dest: webidentity
リクエストを受信すると、サーバーは次の処理を行う必要があります。
client_id
の RP を決定します。- クライアント メタデータでレスポンスします。
クライアント メタデータ エンドポイントのプロパティは次のとおりです。
プロパティ | 説明 |
---|---|
privacy_policy_url (任意) |
RP プライバシー ポリシーの URL。 |
terms_of_service_url (任意) |
RP の利用規約の URL。 |
ブラウザは、エンドポイントからの JSON レスポンスを想定しています。
{
"privacy_policy_url": "https://rp.example/privacy_policy.html",
"terms_of_service_url": "https://rp.example/terms_of_service.html",
}
返されたクライアント メタデータはブラウザによって使用され、RP では使用できません。
ID アサーション エンドポイント
IdP の ID アサーション エンドポイントは、ログインしているユーザーのアサーションを返します。ユーザーが navigator.credentials.get()
呼び出しを使用して RP ウェブサイトにログインすると、ブラウザは SameSite=None
およびコンテンツ タイプ application/x-www-form-urlencoded
を含む Cookie を含む POST
リクエストを、次の情報とともにこのエンドポイントに送信します。
プロパティ | 説明 |
---|---|
client_id (必須) |
RP のクライアント ID。 |
account_id (必須) |
ログイン ユーザーの一意の ID。 |
nonce (任意) |
RP によって提供されるリクエストのノンス。 |
disclosure_text_shown |
結果は(ブール値ではなく)"true" または "false" の文字列になります。開示テキストが表示されなかった場合、結果は "false" になります。これは、アカウント エンドポイントからのレスポンスの approved_clients プロパティ リストに RP のクライアント ID が含まれている場合、または approved_clients がないにもかかわらず過去に登録の瞬間をブラウザで確認した場合に発生します。 |
is_auto_selected |
RP で自動再認証が実行される場合、is_auto_selected は "true" を示します。それ以外の場合は "false" です。これは、より多くのセキュリティ関連機能をサポートするのに役立ちます。たとえば、認証時に明示的なユーザー メディエーションを必要とするより高いセキュリティ階層をユーザーが希望する場合があります。IdP がこのようなメディエーションなしでトークン リクエストを受け取った場合は、リクエストの処理方法が異なる可能性があります。たとえば、RP が mediation: required で FedCM API を再度呼び出せるようにするエラーコードを返します。 |
HTTP ヘッダーの例:
POST /assertion.php HTTP/1.1
Host: accounts.idp.example
Origin: https://rp.example/
Content-Type: application/x-www-form-urlencoded
Cookie: 0x23223
Sec-Fetch-Dest: webidentity
account_id=123&client_id=client1234&nonce=Ct60bD&disclosure_text_shown=true&is_auto_selected=true
リクエストを受信すると、サーバーは次の処理を行う必要があります。
- CORS(クロスオリジン リソース シェアリング)を使用してリクエストに応答します。
- リクエストに
Sec-Fetch-Dest: webidentity
HTTP ヘッダーが含まれていることを確認します。 Origin
ヘッダーを、client_id
によって決定された RP 送信元と照合します。一致しない場合は拒否する。account_id
を、すでにログインしているアカウントの ID と照合します。一致しない場合は拒否します。- トークンで応答します。リクエストが拒否された場合は、エラー レスポンスで応答します。
トークンの発行方法は IdP により異なりますが、通常は、アカウント ID、クライアント ID、発行元、nonce
などの情報で署名されるため、RP はトークンが本物であることを確認できます。
ブラウザは、次のプロパティを含む JSON レスポンスを想定しています。
プロパティ | 説明 |
---|---|
token (必須) |
トークンは、認証に関するクレームを含む文字列です。 |
{
"token": "***********"
}
返されたトークンはブラウザによって RP に渡され、RP は認証を検証できます。
エラー レスポンスを返す
id_assertion_endpoint
は「error」レスポンスも返すことができます。これには 2 つのオプション フィールドがあります。
code
: IdP は、OAuth 2.0 の指定エラーリスト(invalid_request
、unauthorized_client
、access_denied
、server_error
、temporarily_unavailable
)から既知のエラーのいずれかを選択するか、任意の文字列を使用できます。後者の場合、Chrome は一般的なエラー メッセージとともにエラー UI をレンダリングし、コードを RP に渡します。url
: エラーに関する情報を含む、人が読める形式のウェブページを識別し、エラーに関する追加情報をユーザーに提供します。ブラウザはネイティブ UI にリッチエラー メッセージを表示できないため、このフィールドはユーザーにとって有用です。たとえば、次のステップ、カスタマー サービスの連絡先情報などのリンクです。ユーザーがエラーの詳細と修正方法を確認したい場合は、ブラウザの UI から表示されたページにアクセスすると、詳細を確認できます。URL は IdPconfigURL
と同じサイトのものである必要があります。
// id_assertion_endpoint response
{
"error" : {
"code": "access_denied",
"url" : "https://idp.example/error?type=access_denied"
}
}
エンドポイントを切断
IdentityCredential.disconnect()
を呼び出すと、ブラウザは SameSite=None
とコンテンツ タイプ application/x-www-form-urlencoded
を含むクロスオリジンの POST
リクエストを、次の情報とともにこの切断エンドポイントに送信します。
プロパティ | 説明 |
---|---|
account_hint |
IdP アカウントのヒントです。 |
client_id |
RP のクライアント ID。 |
POST /disconnect.php HTTP/1.1
Host: idp.example
Origin: rp.example
Content-Type: application/x-www-form-urlencoded
Cookie: 0x123
Sec-Fetch-Dest: webidentity
account_hint=account456&client_id=rp123
リクエストを受信すると、サーバーは次の処理を行う必要があります。
- CORS(クロスオリジン リソース シェアリング)を使用してリクエストに応答します。
- リクエストに
Sec-Fetch-Dest: webidentity
HTTP ヘッダーが含まれていることを確認します。 Origin
ヘッダーを、client_id
によって決定された RP 送信元と照合します。一致しない場合は拒否する。account_hint
を、すでにログインしているアカウントの ID と照合します。- ユーザー アカウントを RP から切断します。
- 識別されたユーザー アカウント情報を JSON 形式でブラウザに応答します。
レスポンスの JSON ペイロードの例を次に示します。
{
"account_id": "account456"
}
IdP がブラウザに対して RP に関連付けられているすべてのアカウントの接続を解除する場合は、どのアカウント ID とも一致しない文字列を渡します(例: "*"
)。
ログイン URL
Login Status API を使用して、IdP がユーザーのログイン ステータスをブラウザに通知する必要があります。ただし、セッションの有効期限が切れたときなど、ステータスが同期されていない可能性があります。このようなシナリオでは、ブラウザは、idp 構成ファイルの login_url
で指定されたログインページ URL を介して、ユーザーが IdP に動的にログインできるようにします。
次の図に示すように、FedCM ダイアログにはログインを提案するメッセージが表示されます。
ユーザーが [続行] ボタンをクリックすると、ブラウザで IdP のログインページのポップアップ ウィンドウが開きます。
このダイアログは、ファーストパーティの Cookie が設定された通常のブラウザ ウィンドウです。ダイアログ内で何が行われるかは IdP に委ねられ、RP ページへのクロスオリジン通信リクエストに使用できるウィンドウ ハンドルはありません。ユーザーがログインすると、IdP は次のことを行います。
Set-Login: logged-in
ヘッダーを送信するか、navigator.login.setStatus("logged-in")
API を呼び出して、ユーザーがログインしたことをブラウザに通知します。IdentityProvider.close()
を呼び出してダイアログを閉じます。
ID プロバイダでのユーザーのログイン ステータスをブラウザに知らせる
Login Status API は、ウェブサイト(特に IdP)が IdP でのユーザーのログイン ステータスをブラウザに通知するメカニズムです。この API を使用すると、ブラウザは IdP への不要なリクエストを減らし、タイミング攻撃の可能性を軽減できます。
IdP は、ユーザーが IdP にログインしたとき、またはユーザーがすべての IdP アカウントからログアウトしたときに、HTTP ヘッダーを送信するか、JavaScript API を呼び出して、ユーザーのログイン ステータスをブラウザに通知できます。ブラウザは、IdP(構成 URL で識別される)ごとに、ログイン状態を表すトライステート変数を保持します(有効な値は logged-in
、logged-out
、unknown
)。デフォルトの状態は unknown
です。
ユーザーがログインしていることを示すには、トップレベル ナビゲーションで Set-Login: logged-in
HTTP ヘッダーを送信するか、IdP オリジンで同一サイトのサブリソース リクエストを送信します。
Set-Login: logged-in
または、トップレベル ナビゲーションの IdP オリジンから JavaScript API navigator.login.setStatus("logged-in")
を呼び出します。
navigator.login.setStatus("logged-in")
これらの呼び出しにより、ユーザーのログイン ステータスが logged-in
として記録されます。ユーザーのログイン ステータスが logged-in
に設定されている場合、FedCM を呼び出す RP は IdP のアカウント エンドポイントにリクエストを行い、FedCM ダイアログで利用可能なアカウントをユーザーに表示します。
ユーザーがすべてのアカウントからログアウトしたことを通知するには、トップレベル ナビゲーションで Set-Login:
logged-out
HTTP ヘッダーを送信するか、IdP 送信元で同一サイトのサブリソース リクエストを送信します。
Set-Login: logged-out
または、トップレベル ナビゲーションの IdP オリジンから JavaScript API navigator.login.setStatus("logged-out")
を呼び出します。
navigator.login.setStatus("logged-out")
これらの呼び出しにより、ユーザーのログイン ステータスが logged-out
として記録されます。ユーザーのログイン ステータスが logged-out
の場合、FedCM の呼び出しは通知なく失敗します。IdP のアカウント エンドポイントにリクエストを行うことはありません。
unknown
ステータスは、IdP が Login Status API を使用してシグナルを送信する前に設定されます。この API の出荷時にユーザーがすでに IdP にログインしていた可能性があるため、移行を改善するために Unknown
が導入されました。FedCM が最初に呼び出されるまでに、IdP がブラウザにこれを通知できない可能性があります。この場合、Chrome は IdP のアカウント エンドポイントにリクエストを行い、アカウント エンドポイントからのレスポンスに基づいてステータスを更新します。
- エンドポイントから有効なアカウントのリストが返された場合は、ステータスを
logged-in
に更新し、FedCM ダイアログを開いてそれらのアカウントを表示します。 - エンドポイントからアカウントが返されない場合は、ステータスを
logged-out
に更新し、FedCM の呼び出しを失敗します。
ユーザーが動的ログインフローでログインできるようにする
IdP がユーザーのログイン ステータスをブラウザに通知し続けても、セッションの有効期限が切れるなどして同期されていない可能性があります。ログイン ステータスが logged-in
の場合、ブラウザは認証済みリクエストをアカウント エンドポイントに送信しようとしますが、セッションが利用できなくなっているため、サーバーからアカウントが返されません。このようなシナリオでは、ブラウザでポップアップ ウィンドウでユーザーが IdP にログインできるように動的にできます。
ID プロバイダを使用して証明書利用者にログインする
IdP の構成とエンドポイントが利用可能になると、RP は navigator.credentials.get()
を呼び出して、ユーザーが IdP を使用して RP にログインできるようにするようリクエストできます。
API を呼び出す前に、[ユーザーのブラウザで FedCM を使用できる] ことを確認する必要があります。FedCM が使用可能かどうかを確認するには、このコードを FedCM 実装にラップします。
if ('IdentityCredential' in window) {
// If the feature is available, take action
}
ユーザーに RP から IdP へのログインを許可するようリクエストするには、次のようにします。
const credential = await navigator.credentials.get({
identity: {
providers: [{
configURL: 'https://accounts.idp.example/config.json',
clientId: '********',
nonce: '******'
}]
}
});
const { token } = credential;
providers
プロパティは、次のプロパティを持つ IdentityProvider
オブジェクトの配列を受け取ります。
プロパティ | 説明 |
---|---|
configURL (必須) |
IdP 構成ファイルのフルパス。 |
clientId (必須) |
IdP によって発行された RP のクライアント ID。 |
nonce (任意) |
この特定のリクエストに対してレスポンスが発行されるようにするためのランダムな文字列。リプレイ攻撃を防ぎます。 |
loginHint (任意) |
アカウント エンドポイントによって提供される login_hints 値のいずれかを指定すると、指定したアカウントが FedCM ダイアログに選択的に表示されます。 |
domainHint (任意) |
アカウント エンドポイントから提供される domain_hints 値のいずれかを指定すると、FedCM ダイアログに、指定したアカウントが選択的に表示されます。 |
ブラウザによる登録とログインのユースケースの処理は、アカウント リスト エンドポイントからのレスポンスに approved_clients
が存在するかどうかによって異なります。ユーザーがすでに RP に登録している場合、ブラウザに開示テキスト「To continue with ....」は表示されません。
登録の状態は、次の条件が満たされているかどうかに基づいて決定されます。
approved_clients
に RP のclientId
が含まれている場合。- ユーザーがすでに RP に登録済みであることをブラウザが記憶している場合。
RP が navigator.credentials.get()
を呼び出すと、次のアクティビティが行われます。
- ブラウザがリクエストを送信し、複数のドキュメントを取得します。
- well-known ファイルと IdP 構成ファイル。エンドポイントを宣言する。
- アカウント リスト。
- 省略可: クライアント メタデータ エンドポイントから取得される RP のプライバシー ポリシーと利用規約の URL。
- ブラウザには、ユーザーがログインに使用できるアカウントのリストと、利用規約とプライバシー ポリシーが表示されます(利用可能な場合)。
- ユーザーがログインに使用するアカウントを選択すると、ID アサーション エンドポイントへのリクエストが IdP に送信され、トークンが取得されます。
- RP はトークンを検証してユーザーを認証できます。
RP は FedCM をサポートしていないブラウザをサポートすることが想定されているため、ユーザーは FedCM 以外の既存のログイン プロセスを使用できます。サードパーティ Cookie が段階的に廃止されるまでは、問題はありません。
トークンが RP サーバーによって検証されると、RP はユーザーを登録するか、ログインして新しいセッションを開始できるようにします。
Login Hint API
ユーザーがログインした後、証明書利用者(RP)がユーザーに再認証を求めることがあります。ただし、ユーザーがどのアカウントを使用しているかわからない場合があります。 RP でログインに使用するアカウントを指定できると、ユーザーがアカウントを選択しやすくなります。
次のコードサンプルに示すように、RP は、アカウント リスト エンドポイントから取得した login_hints
値のいずれかを使用して、loginHint
プロパティで navigator.credentials.get()
を呼び出すことで、特定のアカウントを選択的に表示できます。
return await navigator.credentials.get({
identity: {
providers: [{
configURL: "https://idp.example/manifest.json",
clientId: "123",
nonce: nonce,
loginHint : "demo1@example.com"
}]
}
});
loginHint
に一致するアカウントがない場合、FedCM ダイアログにログイン プロンプトが表示されます。ユーザーはこのプロンプトを使用して、RP からリクエストされたヒントに一致する IdP アカウントにログインできます。ユーザーがプロンプトをタップすると、構成ファイルで指定されたログイン URL でポップアップ ウィンドウが開きます。リンクには、ログインヒントとドメインヒントのクエリ パラメータが追加されます。
Domain Hint API
特定のドメインに関連付けられたアカウントのみがサイトにログインできることを RP がすでに知っている場合もあります。これは、アクセス先のサイトが企業のドメインに限定されているエンタープライズ シナリオで特に一般的です。ユーザー エクスペリエンスを向上させるため、FedCM API では、RP へのログインに使用できるアカウントのみを RP に表示できます。これにより、ユーザーが企業ドメイン外のアカウントを使用して RP にログインしようとしたときに、適切なタイプのアカウントが使用されなかったために、後でエラー メッセージが表示される(またはログインがうまくいかなかったときに無音状態になる)という事態を回避できます。
次のコードサンプルに示すように、RP は、アカウント リスト エンドポイントから取得した domain_hints
値のいずれかを使用して、domainHint
プロパティで navigator.credentials.get()
を呼び出すことで、一致するアカウントのみを選択的に表示できます。
return await navigator.credentials.get({
identity: {
providers: [{
configURL: "https://idp.example/manifest.json",
clientId: "abc",
nonce: nonce,
domainHint : "corp.example"
}]
}
});
domainHint
に一致するアカウントがない場合、FedCM ダイアログにログイン プロンプトが表示されます。ユーザーはこのプロンプトを使用して、RP からリクエストされたヒントに一致する IdP アカウントにログインできます。ユーザーがプロンプトをタップすると、構成ファイルで指定されたログイン URL でポップアップ ウィンドウが開きます。リンクには、ログインヒントとドメインヒントのクエリ パラメータが追加されます。
エラー メッセージを表示する
IdP が正当な理由でトークンを発行できないことがあります。たとえば、クライアントが許可されていない場合、サーバーが一時的に利用できない場合などです。IdP が「エラー」レスポンスを返した場合、RP はそれをキャッチできます。また、Chrome はブラウザ UI に IdP から提供されたエラー情報を表示して、ユーザーに通知します。
try {
const cred = await navigator.credentials.get({
identity: {
providers: [
{
configURL: "https://idp.example/manifest.json",
clientId: "1234",
},
],
}
});
} catch (e) {
const code = e.code;
const url = e.url;
}
初回認証後にユーザーを自動再認証する
FedCM 自動再認証(略して「自動再認証」)を使用すると、FedCM を使用した初回認証の後、ユーザーが戻ってきたときに自動的に再認証できます。ここでの「初回認証」とは、ユーザーがアカウントを作成するか、同じブラウザ インスタンスで FedCM のログイン ダイアログで [Continue as...] ボタンをタップして RP のウェブサイトにログインすることを意味します。
明示的なユーザー エクスペリエンスは、ユーザーがフェデレーション アカウントを作成する前に、トラッキングを防止するために理にかなっていますが(FedCM の主要な目標の一つです)、ユーザーが一度それを通過した後、不必要に面倒になります。ユーザーが RP と IdP 間の通信を許可する権限を付与した後は、すでに確認したものに対して別の明示的なユーザー確認を適用することで、プライバシーやセキュリティ上のメリットはありません。
自動再認証では、navigator.credentials.get()
を呼び出すときに mediation
に指定したオプションに応じてブラウザの動作が変わります。
const cred = await navigator.credentials.get({
identity: {
providers: [{
configURL: "https://idp.example/fedcm.json",
clientId: "1234",
}],
},
mediation: 'optional', // this is the default
});
// `isAutoSelected` is `true` if auto-reauthn was performed.
const isAutoSelected = cred.isAutoSelected;
mediation
は Credential Management API のプロパティであり、PasswordCredential と FederatedCredential に対して同じ方法で動作し、PublicKeyCredential でも部分的にサポートされています。このプロパティには、次の 4 つの値を指定できます。
'optional'
(デフォルト): 可能であれば自動再認証を行います。できない場合はメディエーションが必要です。ログインページでこのオプションを選択することをおすすめします。'required'
: UI で [続行] ボタンをクリックするなど、続行するために常にメディエーションが必要です。ユーザーが認証の必要があるたびに明示的に権限を付与することが想定される場合は、このオプションを選択します。'silent'
: 可能であれば自動再認証を行います。それ以外の場合は、メディエーションを必要とせず、通知なく失敗します。専用のログインページ以外のページ(配送サイトの商品ページ、ニュース ウェブサイトの記事ページなど)では、このオプションを選択することをおすすめします。'conditional'
: WebAuthn に使用されます。現時点では FedCM では使用できません。
この呼び出しでは、次の条件で自動再認証が行われます。
- FedCM を使用できる。たとえば、ユーザーが FedCM をグローバルにまたは設定で RP に対して無効にしていない。
- ユーザーが FedCM API のアカウントを 1 つだけ使用して、このブラウザでウェブサイトにログインした。
- ユーザーはそのアカウントで IdP にログインしています。
- 自動再認証が過去 10 分以内に行われていません。
- 前回のログイン後に RP が
navigator.credentials.preventSilentAccess()
を呼び出していない。
これらの条件が満たされると、FedCM navigator.credentials.get()
が呼び出されるとすぐにユーザーの自動再認証の試行が開始されます。
mediation: optional
の場合、ブラウザのみが認識できる理由により、自動再認証が使用できない場合があります。RP は、isAutoSelected
プロパティを調べることで、自動再認証が実行されているかどうかを確認できます。
これは、API のパフォーマンスを評価し、それに応じて UX を改善するのに役立ちます。また、利用できない場合、明示的なユーザー メディエーション(mediation: required
のフロー)でログインするようユーザーに求められる場合があります。
preventSilentAccess()
でメディエーションを適用する
ログアウト後すぐにユーザーを自動再認証しても、ユーザー エクスペリエンスはあまり良くありません。そのため、FedCM では、この動作を防ぐために、自動再認証の後に 10 分間の待機期間が設けられています。つまり、ユーザーが 10 分以内に再度ログインしない限り、自動再認証は最大で 10 分に 1 回行われます。ユーザーが RP から明示的に(ログアウト ボタンをクリックするなどして)ログアウトしたときに、RP は navigator.credentials.preventSilentAccess()
を呼び出して、自動再認証を無効にするよう明示的にブラウザにリクエストする必要があります。
function signout() {
navigator.credentials.preventSilentAccess();
location.href = '/signout';
}
ユーザーは設定で自動再認証を無効にできます
ユーザーは設定メニューから自動再認証を無効にできます。
- パソコンの Chrome では、[
chrome://password-manager/settings
] > [自動的にログイン] に移動します。 - Android Chrome で [設定] > [パスワード マネージャー] を開き、右上の歯車アイコンをタップして [自動ログイン] を選択します。
切り替えを無効にすると、ユーザーは自動再認証動作をすべてまとめてオプトアウトできます。ユーザーが Chrome インスタンスで Google アカウントにログインしていて、同期が有効になっている場合、この設定はデバイス間で保存および同期されます。
IdP を RP から切断する
ユーザーが以前に FedCM を介して IdP を使用して RP にログインしたことがある場合、関係は接続済みアカウントのリストとしてブラウザによってローカルに記憶されます。RP は IdentityCredential.disconnect()
関数を呼び出すことで接続解除を開始できます。この関数はトップレベル RP フレームから呼び出すことができます。RP は、configURL
、IdP で使用される clientId
、IdP を切断するための accountHint
を渡す必要があります。アカウント ヒントは、接続解除エンドポイントがアカウントを識別できる限り、任意の文字列にできます。たとえば、メールアドレスやユーザー ID は、アカウント リスト エンドポイントが提供するアカウント ID と必ずしも一致しません。
// Disconnect an IdP account "account456" from the RP "https://idp.com/". This is invoked on the RP domain.
IdentityCredential.disconnect({
configURL: "https://idp.com/config.json",
clientId: "rp123",
accountHint: "account456"
});
IdentityCredential.disconnect()
は Promise
を返します。この Promise は、次の理由で例外をスローする場合があります。
- ユーザーが FedCM を通じて IdP を使用して RP にログインしていない。
- FedCM 権限ポリシーのない iframe から API が呼び出されている。
- configURL が無効であるか、切断エンドポイントがありません。
- コンテンツ セキュリティ ポリシー(CSP)のチェックに失敗した。
- 保留中の接続解除リクエストがあります。
- ユーザーがブラウザの設定で FedCM を無効にしている。
IdP の切断エンドポイントがレスポンスを返すと、ブラウザで RP と IdP が接続解除され、Promise が解決されます。切断されたアカウントの ID は、切断エンドポイントからのレスポンスで指定されます。
クロスオリジンの iframe 内から FedCM を呼び出す
FedCM は、親フレームで許可されている場合、identity-credentials-get
権限ポリシーを使用してクロスオリジンの iframe 内から呼び出すことができます。そのためには、次のように allow="identity-credentials-get"
属性を iframe タグに追加します。
<iframe src="https://fedcm-cross-origin-iframe.glitch.me" allow="identity-credentials-get"></iframe>
例で実際の動作を確認できます。
必要に応じて、親フレームがオリジンで FedCM を呼び出すよう制限する場合は、許可されたオリジンのリストを含む Permissions-Policy
ヘッダーを送信します。
Permissions-Policy: identity-credentials-get=(self "https://fedcm-cross-origin-iframe.glitch.me")
権限ポリシーの仕組みについて詳しくは、権限ポリシーでブラウザ機能を制御するをご覧ください。