FedCM を使用してプライバシー保護の ID 連携を行う方法について説明します。
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 を公開します。
既知のファイルを作成する
トラッカーが API を不正使用しないようにするには、IdP の eTLD+1 の /.well-known/web-identity
から well-known ファイルを提供する必要があります。
たとえば、IdP エンドポイントが https://accounts.idp.example/
で提供されている場合、https://idp.example/.well-known/web-identity
にある既知のファイルと 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 が複数のアカウントをサポートしている場合、このエンドポイントはログインしているすべてのアカウントを返します。
ブラウザは、SameSite=None
を含む Cookie を含む GET
リクエストを送信しますが、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
を含む Cookie と 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 で識別される)ごとに、ブラウザはログイン状態を表す 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 ダイアログに表示します。
ユーザーがすべてのアカウントからログアウトしたことを通知するには、最上位のナビゲーションまたは IdP オリジンの同一サイトのサブリソース リクエストで Set-Login:
logged-out
HTTP ヘッダーを送信します。
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 にログインしていた可能性があるため、移行を適切に行うために導入されました。IdP は、FedCM が最初に呼び出されるまでに、ブラウザにこれを通知できない可能性があります。この場合、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 から「エラー」レスポンスが返された場合、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
は 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 アカウントにログインし、同期が有効になっている場合、この設定はデバイス間で保存され、同期されます。
RP から IdP を切断する
ユーザーが以前に 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
を返します。このプロミスは、次の理由で例外をスローすることがあります。
- ユーザーが FedCM 経由で IdP を使用して RP にログインしていない。
- API が FedCM 権限ポリシーのない iframe 内から呼び出されている。
- configURL が無効であるか、切断エンドポイントがありません。
- コンテンツ セキュリティ ポリシー(CSP)チェックが失敗します。
- 保留中の接続解除リクエストがあります。
- ユーザーがブラウザの設定で FedCM を無効にしている。
IdP の切断エンドポイントがレスポンスを返すと、ブラウザで RP と IdP が切断され、Promise が解決されます。切断されたアカウントの ID は、切断エンドポイントからのレスポンスで指定されます。
クロスオリジン iframe 内から FedCM を呼び出す
親フレームが許可している場合、identity-credentials-get
権限ポリシーを使用して、クロスオリジン iframe 内から FedCM を呼び出すことができます。そのためには、次のように 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")
権限ポリシーの仕組みについて詳しくは、権限ポリシーによるブラウザ機能の制御をご覧ください。