プライバシーに配慮した 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 をブロック] を選択します。モバイルの場合は、[設定] > [サイト設定] > [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 ファイルには、IdP 構成ファイルの URL の配列を含む provider_urls
プロパティを含める必要があります。この URL は、RP が navigator.credentials.get
の configURL
のパス部分として指定できます。配列内の 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 にログイン済みである可能性があるため、スムーズな移行を実現するために導入されました。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
を返します。このプロミスは、次の理由で例外をスローすることがあります。
- ユーザーが 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")
権限ポリシーの仕組みについて詳しくは、権限ポリシーによるブラウザ機能の制御をご覧ください。