プライバシーに配慮した ID 連携に FedCM を使用する方法を学習する。
FedCM(Federated Credential Management)は、ID 連携サービス(「~でログイン」など)へのプライバシーを保護したアプローチの提案です。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
)またはモバイルで [設定] > [サイトの設定] > [Cookie] に移動して、[サードパーティの Cookie をブロックする] を選択します。
FedCM API の使用
FedCM と統合するには、アカウント リスト、アサーションの発行、必要に応じてクライアント メタデータの既知のファイル、構成ファイルとエンドポイントを作成します。
そこから、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 が含まれておらず、リダイレクトに従わない。これにより、リクエストを行ったユーザーと接続を試行している RP を IdP が学習するのを効果的に防ぐことができます。例:
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 (任意) |
ログイン ダイアログに表示されるアイコン オブジェクトを設定するブランディング オプション。icon オブジェクトは、次の 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 が複数のアカウントをサポートしている場合、このエンドポイントはログインしているすべてのアカウントを返します。
ブラウザは、 GET
リクエストを SameSite=None
を含む Cookie で送信しますが、client_id
パラメータ、Origin
ヘッダー、 Referer
ヘッダーはなしにします。これにより、ユーザーがログインしようとしている RP を IdP が知ることを効果的に防ぐことができます。例:
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 で RP にまだ登録していない場合に、ログイン ダイアログに表示されます。
ブラウザは、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
の Cookie と application/x-www-form-urlencoded
のコンテンツ タイプを含む POST
リクエストを、次の情報を付けてこのエンドポイントに送信します。
プロパティ | 説明 |
---|---|
client_id (必須) |
RP のクライアント ID。 |
account_id (必須) |
ログイン中のユーザーの一意の ID。 |
nonce (任意) |
RP から提供されるリクエスト ノンス。 |
disclosure_text_shown |
結果はブール値ではなく、"true" または "false" の文字列になります。開示テキストが表示されなかった場合、結果は "false" になります。これは、RP のクライアント ID がアカウントのエンドポイントからのレスポンスの approved_clients プロパティ リストに含まれていた場合、またはブラウザで 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
の Cookie を含むクロスオリジン 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 で識別される)ログイン状態を表す 3 値の可変を保持します。値は logged-in
、logged-out
、unknown
です。デフォルトの状態は unknown
です。
ユーザーがログインしていることを通知するには、IdP オリジンの最上位ナビゲーションまたは同一サイトのサブリソース リクエストで Set-Login: logged-in
HTTP ヘッダーを送信します。
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 を使用してシグナルを送信する前に設定されます。Unknown
は、この API がリリースされた時点でユーザーが IdP にログインしている可能性があるため、スムーズな移行を実現するために導入されました。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 に登録している場合、ブラウザには開示テキスト「... に続行するには」は表示されません。
登録ステータスは、次の条件が満たされているかどうかに基づいて決定されます。
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 から「error」レスポンスが返された場合、RP はそれをキャッチできます。また、Chrome は、IdP から提供されたエラー情報を含むブラウザ UI を表示してユーザーに通知します。
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 自動再認証(略して「auto-reauthn」)を使用すると、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
は 認証情報管理 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 にログインしていない。
- API が FedCM 権限ポリシーのない iframe 内から呼び出されている。
- configURL が無効か、切断エンドポイントがありません。
- コンテンツ セキュリティ ポリシー(CSP)のチェックに失敗する
- 保留中の切断リクエストがあります。
- ユーザーがブラウザの設定で FedCM を無効にしている。
IdP の切断エンドポイントがレスポンスを返すと、ブラウザで RP と IdP の接続が切断され、Promise が解決されます。切断されたアカウントの ID は、切断エンドポイントからのレスポンスで指定されます。
クロスオリジンの iframe 内から FedCM を呼び出す
FedCM は、親フレームで許可されている場合、identity-credentials-get
権限ポリシーを使用してクロスオリジン iframe 内から呼び出すことができます。そのためには、次のように iframe タグに allow="identity-credentials-get"
属性を追加します。
<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")
権限ポリシーの仕組みについて詳しくは、権限ポリシーによるブラウザ機能の制御をご覧ください。