1. はじめに
このセクションは規範的ではありません。
ウェブの進化に伴い、プライバシー重視の変更が継続的に行われてきました (例:Safari、Firefox、 Chrome) および基礎となるプライバシー原則の変更(例:Privacy Model)。
この進化によって、ウェブプラットフォームの基本的な仮定が再定義または廃止されています。サードパーティコンテキストでのCookieへのアクセスもその仮定のひとつです。ウェブ全体にとって良いことである一方、サードパーティCookieの廃止は、特定のフェデレーション認証設計で利用されていた基本的な構成要素を失うことになります。
Federated Credential Management APIは、サードパーティCookieに依存していたフェデレーション認証設計のためのギャップを埋めることを目的としています。 このAPIは、サードパーティCookieに依存するフェデレーション認証をサインインからサインアウト、取り消しまでサポートするために必要なプリミティブを提供します。
サードパーティCookieを使用せずにフェデレーション認証のプリミティブを提供するために、APIはユーザーエージェントを RP(フェデレーションサインインのためにユーザー情報を要求するウェブサイト)と IDP(フェデレーションサインインのためにユーザー情報を提供するウェブサイト)の間の媒介者として配置します。この媒介には、RPとIDPがユーザーとの接続を認識する前に、ユーザーの許可が必要です。
この仕様はユーザーエージェントやIDPの変更に大きく依存し、RPへの依存は最小限です。FedCM APIは認証やトークン取得の手段を提供します。
< html > < head > < title > Welcome to my Website</ title > </ head > < body > < button onclick = "login()" > Login with idp.example</ button > < script > let nonce; async function login() { try { // ランダムな数値を返すメソッドがあると仮定します。値を変数に保存し、 // 後でトークンに含まれる値と照合できます。 nonce= random(); // ユーザーにIDPのアカウント選択を促し、RPでフェデレーションログインを行います。 // 成功すると、PromiseはIdentityCredentialオブジェクトを返し、|token|を // 取得できます。これはIDPからRPへ渡される不透明な文字列です。 let token= await navigator. credentials. get({ identity: { providers: [{ configURL: "https://idp.example/manifest.json" , clientId: "123" , nonce: nonce, }] } }); } catch ( e) { // FedCM呼び出しは成功しませんでした。 } } </ script > </ body > </ html >
概要として、Federated Credential Management APIは協調するIDPとRPの仲介によって機能します。
§ 3 Identity Provider HTTP APIでは、IDPが公開するHTTP APIセットと、§ 2 The Browser APIで利用できるエントリーポイントを定義しています。
ユーザーエージェントは、APIがトラッキング目的で利用されることを非現実的にするよう仲介しつつ、認証連携の機能性を維持します。
2. ブラウザーAPI
ブラウザーAPIはRPとIDPが呼び出せるAPIを公開し、ユーザーのID交換を仲介します。
サインアップ/サインインAPIはRPが ブラウザーにIDPとの関係仲介と トークンの発行を依頼するために使われます。
注: RPはサインアップとサインインを区別せず、同じAPIを区別なく呼び出します。
すべてが正常に進行すると、Relying Partyにはユーザー認証に使えるトークンを含むIdentityCredential
が返却されます。
const credential= await navigator. credentials. get({ identity: { providers: [{ configURL: "https://idp.example/manifest.json" , clientId: "123" , }] } });
Cookie付きで送信されるフェッチでは、リソースが同一オリジンリクエストとしてロードされた場合と同様に、分割されていないCookieが含まれます。 これは、SameSite 値(サードパーティとしてリソースがロードされた場合に使われる)に関係なく、です。これにより、IDPがFedCM APIを採用しやすくなります。APIではRPがフェッチの結果を参照できないため、セキュリティ上の問題はありません。
2.1. ログインステータスAPI
2.1.1. ログインステータスマップ
各ユーザーエージェントは、グローバルかつ永続的なログインステータスマップ(初期値は空のmap)を保持します。このmapのキーはorigin(IDPのorigin)であり、値は、"unknown"、"logged-in"、
"logged-out"のいずれかのenumです。
-
ログインステータスマップ[origin]が存在すれば、それを返す。
-
それ以外の場合は、unknownを返す。
-
valueがlogged-inまたはlogged-outのいずれかであることを確認する。
-
Set ログインステータスマップ[origin]をvalueに設定する。
2.1.2. インフラストラクチャアルゴリズム
trueを返す場合である:
-
settingsのrelevant global objectに関連付けられたDocumentがなければ、
falseを返す。 -
documentをsettingsのrelevant global objectの関連付けられたDocumentとする。
-
documentにbrowsing contextがなければ、
falseを返す。 -
originをsettingsのoriginとする。
-
navigableをdocumentのnode navigableとする。
-
navigableがnullでない親を持つ間:
-
navigableをnavigableの親に設定する。
-
navigableのactive documentのoriginがoriginと同一サイトでなければ、
falseを返す。
-
-
trueを返す。
2.1.3. HTTPヘッダーAPI
IDPは、以下のようにHTTPレスポンスのヘッダーを利用してログインステータスを設定できます。
HTTPヘッダーのチェックはFetch仕様で扱われるべきです。すべてのリソースロードに影響するためです。
各http-redirect fetchおよびhttp
fetchのレスポンスごとに、valueをレスポンスのヘッダーリストから
"Set-Login"という名前・"item"型で
構造化フィールド値の取得を行った結果とする。valueがnullでなければ、以下の手順でこのヘッダーを処理する:
-
リクエストのdestinationが
"document"でなければ: -
valueがタプルであることを確認する。
-
tokenをvalueの最初の要素とする。
-
tokenが
"logged-out"なら、originのログインステータスをlogged-outに設定する。
2.1.4. JavaScript API
IDPは、保存されたログインステータスを更新するためのJavaScript APIも利用できます:
enum {LoginStatus ,"logged-in" , }; ["logged-out" Exposed =Window ,SecureContext ]interface {NavigatorLogin Promise <undefined >(setStatus LoginStatus ); };status partial interface Navigator { [SecureContext ]readonly attribute NavigatorLogin ; };login
setStatus()
が引数statusで呼び出されたとき:
-
current settings objectが祖先と同一サイトでなければ、
SecurityErrorDOMExceptionをthrowする。 -
originをcurrent settings objectのoriginとする。
-
valueをstatusが
"logged-in"ならlogged-in、"logged-out"ならlogged-outとする。 -
originのログインステータスをvalueに設定する。
2.1.5. ログインステータスマップデータのクリア
ユーザーエージェントは以下の場合にもログインステータスマップデータをクリアしなければなりません:
- ユーザーがすべてのCookieまたはサイト設定データをクリアした場合
-
ユーザーエージェントはマップ全体をクリアしなければなりません。
- ユーザーが特定のoriginのすべてのCookieまたは全サイトデータをクリアした場合
-
ユーザーエージェントは、削除されたCookieが送信可能なoriginに対するすべてのエントリを削除しなければなりません。
注: 例えば、ドメインCookieは削除されたoriginのサブドメインにも影響する場合があります。
google.comのCookieをクリアすると、accounts.google.comのログインステータスもリセットされるべきです。 これはgoogle.comのドメインCookieに依存している可能性があるためです。 - ユーザーが個別のCookieを削除した場合(ユーザーエージェントが許可する場合)
-
動作はユーザーエージェント定義です。
注: ユーザーエージェントは状態をunknownにリセットしたい場合があります。 これは、そのCookieが認可状態に影響するかどうか判断できないためです。
- ユーザーエージェントがClear-Site-Dataヘッダーを
"cookies"または"*"として受信し、requestのclientがnullでなく、clientのoriginが同一originかつトップレベルoriginである場合 -
originのCookieクリア中は、ログインステータスマップの キーが入力originであるエントリを削除する必要があります。
Clear-Site-Dataがpartitioned cookiesをサポートした場合、この文言を更新する必要があります。
注: 他のウェブサイトが起因するCookie変更はこのマップに影響しないはずです。IDPのログイン状態が変化した際は明示的にSet-Loginヘッダーを送信すべきです。RPの状態はこのマップに影響しません。このマップはIDPの状態のみを反映します。
2.2. 接続済みアカウントセット
各ユーザーエージェントは、グローバルな接続済みアカウントセット(初期値は空の順序付きセット)を持ちます。要素は(rp, idp, account)の三つ組で、rpはRPのorigin、idpはIDPのorigin、accountはアカウント識別子を表す文字列です。このセットは、ユーザーがFedCMを使用してidpのaccountでrpにログインした三つ組の集合を示します。
接続済みアカウントセットはRPで二重キー化されるべきです(つまり、リクエスターと埋め込み元両方、iframeとトップレベルの両方を含むべきです)。そうしないと、トップレベルの状態が埋め込み元によって利用・変更され、リークや不要なクロスオリジン通信が発生します。
ユーザーがoriginの閲覧データ(Cookie、localStorageなど)をクリアした場合、ユーザーエージェントはremoveを用いてoriginに一致する三つ組を接続済みアカウントセットから全て削除しなければなりません。
IdentityProviderConfig
provider、IdentityProviderAccount
account、globalObjectを受け取って以下を実行。(rp, idp,
account)の三つ組を返す。
IdentityProviderAccount
accountが自動再認証対象かどうか:IdentityProviderConfig
providerとglobalObjectを受けて以下を実行。Booleanを返す。
-
accountが
approved_clientsを含み、かつaccountのapproved_clientsがproviderのclientIdを含まないなら、falseを返す。 -
tripleをconnected account keyの算出でprovider、account、globalObjectを渡して得る。
-
接続済みアカウントセットがtripleを含む場合、その値を返す。
IdentityProviderAccount
account、IdentityProviderConfig
provider、globalObjectを渡して以下を実行。
connectedまたはdisconnectedを返す。
-
accountが
approved_clientsを含む場合:-
accountの
approved_clientsがproviderのclientIdを含むなら、connectedを返す。 -
disconnectedを返す。
-
-
tripleをconnected account keyの算出でprovider、account、globalObjectを渡して得る。
-
接続済みアカウントセットがtripleを含む場合、connectedを返す。
-
disconnectedを返す。
IdentityProviderConfig
provider、IdentityProviderAccount
account、globalObject(RPのもの)を渡して以下を実行:
-
configUrlをproviderの
configURLとglobalObjectでparse urlを実行した結果とする。 -
idpOriginをconfigUrlに対応するoriginとする。
-
rpOriginをglobalObjectのassociated Documentのoriginとする。
-
accountIdをaccountの
idとする。 -
tripleを(rpOrigin, idpOrigin, accountId)とする。
-
Append tripleを接続済みアカウントセットに追加する。
-
tripleを(rpOrigin, idpOrigin, accountId)とする。
-
接続済みアカウントセットがtripleを含む場合:
-
Remove tripleを接続済みアカウントセットから削除する。
-
trueを返す。
-
-
falseを返す。
-
すべての(rp, idp, accountId)tripleを接続済みアカウントセットでループ:
-
rpがrpOriginと等しく、かつidpがidpOriginと等しい場合、remove tripleを接続済みアカウントセットから削除する。
-
2.3. IdentityCredentialインターフェース
この仕様は新しいCredential型である
IdentityCredentialを導入します:
dictionary :IdentityCredentialDisconnectOptions IdentityProviderConfig {required USVString ; }; [accountHint Exposed =Window ,SecureContext ]interface :IdentityCredential Credential {static Promise <undefined >(disconnect optional IdentityCredentialDisconnectOptions = {});options readonly attribute USVString ?;token readonly attribute boolean ; };isAutoSelected
id-
idの 属性getterは空文字列を返します。 tokenisAutoSelected-
isAutoSelectedの 属性getterは設定された値を返します。これはUIフローでユーザーのIDクレデンシャルが自動選択されたかどうかを示します。 その結果このIdentityCredentialが生成されました。 [[type]]-
IdentityCredentialの[[type]]の 値は"identity"です。 [[discovery]]
本仕様の主なエントリポイントは、Credential Management APIが公開するエントリポイントを通じて利用します。
2.3.1. disconnectメソッド
disconnect
メソッドがIdentityCredentialDisconnectOptions
optionsで呼び出された場合、以下の手順を実行する:
-
globalObjectを現在のグローバルオブジェクトとする。
-
documentをglobalObjectの関連付けられたDocumentとする。
-
documentがallowed to useのidentity-credentials-get ポリシー制御機能の利用が許可されていない場合、"
NotAllowedError"DOMExceptionをthrowする。 -
promiseを新しい
Promiseとする。 -
promiseを返す。
IdentityCredentialDisconnectOptions
options、Promise
promise、globalObjectで呼び出された場合、以下の手順を実行する:
-
Assert: これらの手順は並列で動作している。
-
configUrlをoptionsの
configURLとglobalObjectでparse urlを実行した結果とする。 -
configUrlが失敗なら、reject promiseを"
InvalidStateError"DOMExceptionでrejectする。 -
Content Security Policy Level 3のconnect-srcディレクティブでconfigUrlに対してチェックを行う。失敗した場合は、reject promiseを"
NetworkError"DOMExceptionでrejectする。 -
このglobalObjectに対して他に保留中の
disconnect呼び出しがある場合(例:例外がまだthrowされていない、または関連するPromiseがまだ解決されていない場合)、reject promiseを"NetworkError"DOMExceptionでrejectする。 -
configUrlがpotentially trustworthy originでなければ、reject promiseを "
NetworkError"DOMExceptionでrejectする。 -
ユーザーがglobalObjectでFedCM APIを無効にしている場合、reject promiseを "
NetworkError"DOMExceptionでrejectする。 -
アカウントaccountが存在せず、接続済みアカウントセットが含む値としてconnected account keyの算出でaccount、options、globalObjectを渡して得た値がなければ、reject promiseを"
NetworkError"DOMExceptionでrejectする。 このチェックは接続済みアカウントセットをイテレートするか、高速化のため別データ構造を保持してもよい。 -
configをproviderとglobalObjectで設定ファイル取得を実行した結果とする。
-
configが失敗なら、reject promiseを"
NetworkError"DOMExceptionでrejectする。 -
disconnectUrlをprovider、config.
disconnect_endpoint、globalObjectでmanifest URL算出を実行した結果とする。 -
disconnectUrlが失敗なら、reject promiseを"
NetworkError"DOMExceptionでrejectする。 -
切断リクエスト送信をdisconnectUrl、options、globalObjectで実行し、その結果をresultとする。
-
idpOriginをconfigUrlに対応するoriginとする。
-
rpOriginをglobalObjectの関連付けられたDocumentのoriginとする。
-
resultが失敗の場合:
-
すべての接続の削除をrpOriginとidpOriginで実行する。
-
reject promiseを"
NetworkError"DOMExceptionでrejectする。 -
return。
-
-
accountIdをresult(失敗でないことに注意)とする。
-
接続の削除をaccountId、rpOrigin、idpOriginで実行し、結果をwasAccountRemovedとする。
-
wasAccountRemovedがfalseなら、すべての接続の削除をrpOriginとidpOriginで実行する。
-
resolve promiseする。
2.3.1.1. 切断リクエスト
切断リクエスト送信アルゴリズムは、RPでフェデレーションログインに使用されたアカウントを切断するためのリクエストを送信します。
IdentityCredentialDisconnectOptions
options、globalObjectで呼び出された場合、以下の手順を実行。この処理はUSVString
または失敗を返す。
-
requestBodyをurlencoded serializerでリスト
-
("client_id", optionsの
clientId) -
("account_hint", optionsの
accountHint)
-
-
requestを新しいrequestとして以下の通り作成:
- url
-
disconnectUrl
- method
-
"POST"
- body
-
UTF-8 encodeされたrequestBody
- redirect mode
-
"error"
- client
-
null
- window
-
"no-window"
- service-workers mode
-
"none"
- destination
-
"webidentity"
- origin
- header list
-
listに、header(nameは
Accept、valueはapplication/x-www-form-urlencoded)を1つだけ含める - credentials mode
-
"include"
- mode
-
"cors"
-
accountIdをnullとする。
-
fetch requestをrequest、globalObjectで実行し、processResponseConsumeBodyは、response responseとresponseBodyを引数に以下の手順を実行する:
-
jsonをresponseとresponseBodyでJSON fetchレスポンス抽出を実行した結果とする。
-
ECMAScript値からIDL値変換でjsonを
DisconnectedAccount型のaccountに変換する。 -
前2ステップのいずれかで例外がthrowされた場合、accountIdに失敗をセットしreturnする。
-
accountIdをaccountの
account_idとする。
-
-
accountIdがセットされるまで待つ。
-
accountIdを返す。
dictionary {DisconnectedAccount required USVString account_id ; };
2.3.2. CredentialRequestOptions
このセクションではJavaScript呼び出し時に渡されるディクショナリを定義します:
const credential= await navigator. credentials. get({ identity: { // IdentityCredentialRequestOptions providers: [{ // sequence<IdentityCredentialRequestOptions> configURL: "https://idp.example/manifest.json" , // IdentityProviderConfig.configURL clientId: "123" , // IdentityProviderConfig.clientId nonce: "nonce" // IdentityProviderConfig.nonce }] } });
この仕様ではCredentialRequestOptions
オブジェクトの拡張を導入します:
partial dictionary CredentialRequestOptions {IdentityCredentialRequestOptions ; };identity
IdentityCredentialRequestOptions
にはRPがサポートし事前登録している(つまり、IDPがRPにclientIdを与えている)IdentityProviderConfigのリストが含まれます。
IdentityCredentialRequestOptions
にはIdentityCredentialRequestOptionsContext
も含まれ、ユーザーエージェントがより意味のあるダイアログをユーザーに提供できます。
enum {IdentityCredentialRequestOptionsContext ,"signin" ,"signup" ,"use" };"continue" dictionary {IdentityCredentialRequestOptions required sequence <IdentityProviderRequestOptions >;providers IdentityCredentialRequestOptionsContext = "signin"; };context
各IdentityProviderConfig
はRPがサポートしている(事前登録済み)IDPを表します。
dictionary {IdentityProviderConfig required USVString ;configURL required USVString ; };clientId dictionary :IdentityProviderRequestOptions IdentityProviderConfig {USVString ;nonce DOMString ;loginHint DOMString ; };domainHint
configURL-
アイデンティティプロバイダーの設定ファイルのURLです。
clientIdnonce-
RPが選択するランダムな数値です。通常はクライアントセッションと
tokenの関連付けやリプレイ攻撃の緩和に使われます。十分なエントロピーがあり、推測困難である必要があります。 loginHint-
RPがユーザーエージェントに表示してほしいアカウントに対応するログインヒントを表す文字列です。指定された場合、ユーザーエージェントはこのログインヒント値に一致しないアカウントを表示しません。通常、希望する
IdentityProviderAccountの属性のいずれかに一致します。 domainHint-
RPが関心を持つドメイン、またはすべてのアカウントを希望する場合は"any"を表す文字列です。指定した場合、一致しないドメインヒントのアカウントは表示されません。
2.3.3.
[[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors) 内部メソッド
[[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors)
アルゴリズムは、Credential
Management
1 § 2.5.1 クレデンシャル要求の内部で並列実行され、クレデンシャルを要求し、IdentityCredential
またはエラーを返します。
この内部メソッドは3つの引数を受け取ります:
origin-
この引数は、呼び出し元の relevant settings object の origin です。これは
get()実装によって決定されます。すなわちCredentialsContainerの Request aCredential抽象操作です。 options-
この引数は
CredentialRequestOptionsオブジェクトで、そのidentityメンバーが 存在します。 sameOriginWithAncestors-
この引数は Boolean 値で、呼び出し元の environment settings object が 祖先と同一オリジン の場合のみ
trueです。クロスオリジンの場合はfalseです。注: この 内部メソッド の呼び出しは、permissions policy によって許可されたことを示します。これは Credential Management Level 1 のレベルで評価されます。 詳細は § 4 Permissions Policy Integration を参照してください。したがって、 sameOriginWithAncestors は未使用です。
options.signal
はリクエストの中断シグナルとして使用されます。
IdentityCredential
の
[[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors)
アルゴリズムが呼び出されたとき、ユーザーエージェントは以下の手順を実行しなければなりません。これは IdentityCredential
を返す(または呼び出し元にエラーを投げる)。
-
Assert: これらの手順は 並列で実行している。
-
options["
identity"]["providers"] のサイズが1でない場合、グローバルタスクをキューし、DOM操作タスクソースでglobalObjectに新しい"NetworkError"DOMExceptionを投げる注: globalObjectは現在
[[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors)アルゴリズムに渡されません。issue参照。 -
ユーザーエージェントは次のステップに進むタイミングを決定できます。
注: 例えば、ユーザーエージェントはネットワークリクエスト前にIDプロバイダー選択画面を表示したり、URLバーにボタンを出してユーザー操作を待ったりできます。
-
credentialをIdentityCredential作成 をprovider、options、globalObjectで実行した結果とする。
-
credentialがペアの場合:
-
2番目の要素値をthrowImmediatelyとする。
-
以下すべて満たす場合、ユーザーエージェントは次のステップまでランダムな時間待つ必要がある:
-
throwImmediatelyがfalse
-
promise拒否遅延がユーザーエージェント自動化により無効化されていない
-
ユーザーエージェントが、RPがアカウントにログインしているかどうかを露呈しないための他の方法を実装していない
注: ここでの意図は、Promiseが即座に解決された場合、RPがダイアログが表示されなかったことをネットワーク遅延のみで推測できてしまうことを防ぐためです。ダイアログ表示があれば、ユーザーが1つ以上のIDPアカウントにログインしていることを示します。この情報漏洩を防ぐため、特にユーザー確認なしで遅延を入れる仕様です。ただし、UAは異なるUIアプローチで防ぐ場合もあります。
-
-
グローバルタスクをキューし、DOM操作タスクソースで新しい"
NetworkError"DOMExceptionを投げる。
-
-
それ以外の場合はcredentialを返す。
2.3.4. IdentityCredentialの作成
IdentityCredential作成アルゴリズムは各種FedCMフェッチを呼び出し、ユーザーエージェントUIを表示し、
IdentityCredential
を生成し、RPに返します。
IdentityProviderRequestOptions
provider、CredentialRequestOptions
options、globalObjectで実行。IdentityCredential
または (failure, bool) のペア(boolは例外遅延スキップ指示)を返す。
-
Assert: これらの手順は 並列で実行している。
-
loginStatusをログインステータス取得で providerの
configURLのoriginを使って得る。 -
loginStatusがunknownなら、ユーザーエージェントはlogged-outに設定してもよい。
-
loginStatusがlogged-outなら、ユーザーエージェントは以下いずれかを行う:
-
(failure, false)を返す。
-
ユーザーに継続するか確認。ユーザーが継続する場合、ユーザーエージェントはloginStatusをunknownに設定すべき。IDPログインダイアログ表示の選択肢も含めることができる。
-
ユーザーがダイアログをキャンセルしたら(failure, true)を返す。
-
ユーザーがこの選択肢を選んだ場合:
-
configを設定ファイル取得でproviderとglobalObjectで得る。
-
configが失敗なら(failure, true)を返す。
-
IDPログインダイアログ表示をconfigとproviderで実行。
-
そのアルゴリズムが失敗なら(failure, true)を返す。
-
-
-
-
requiresUserMediationをproviderの
configURLのoriginのユーザ仲介が必要で得る。 -
mediationをoptionsの
mediationとする。 -
requiresUserMediationがtrueかつmediationが "
silent" なら(failure, true)を返す。 -
configを設定ファイル取得でproviderとglobalObjectで得る。
-
configが失敗なら(failure, false)を返す。
-
アカウント取得ステップ:accountsListをアカウント取得で config、provider、globalObjectで得る。
-
accountsListが失敗またはサイズが0の場合:
-
ログインステータス設定で
configURLのoriginをlogged-outに設定する。 サーバーにクレデンシャルが送信されていない場合、このステップは省略可能。注: 例えば、DNSエラー等でフェッチ失敗の場合は、クレデンシャルが送信されていないため、IDPはユーザーのIDを認識しません。このケースでは、ユーザーがサインインしているかどうか不明のため、ステータスリセット不要な場合もあります。
-
不一致ダイアログステップ:loginStatusがlogged-inの場合、ユーザーにダイアログ表示。内容はユーザーエージェント定義。このダイアログは IDPログインダイアログ表示をconfigとproviderで実行できる選択肢を含むべき。 このダイアログは IDPログイン確認ダイアログ。
注: この状況は、ブラウザがユーザーがサインインしていると予測したものの、アカウント取得でサインアウトが示唆された場合です。
注: このダイアログは、サーバーにクレデンシャルが送信された場合に必ず何らかのUIを表示することで、ユーザーのサイレントトラッキングを不可能にします。
-
以下いずれかになるまで待機:
-
ユーザーがダイアログを閉じたら(failure, true)を返す。
-
IDPログインダイアログ表示が実行された場合:
-
結果をresultとする。
-
resultが失敗なら(failure, true)を返す。ユーザーエージェントは失敗理由を示すダイアログを表示してもよい。
-
それ以外の場合はアカウント取得ステップに戻る。
-
-
-
-
-
Assert: accountsListは失敗でなく、サイズは0でない。
-
providerの
loginHintが空でない場合:-
accountList内の各accountについて、accountの
login_hintsがproviderのloginHintを含まない場合、accountをaccountListから削除。 -
accountListが空になった場合、不一致ダイアログステップへ。
-
-
providerの
domainHintが空でない場合:-
accountList内の各accountについて:
-
domainHintが"any"の場合:-
accountの
domain_hintsが空なら、accountをaccountListから削除。
-
-
それ以外の場合は、accountの
domain_hintsがproviderのdomainHintを含まない場合、accountをaccountListから削除。
-
-
accountListが空になった場合、不一致ダイアログステップへ。
-
-
accountsList内の各accについて:
注: ユーザーエージェントは、初期表示でアカウント画像取得を必要としないUI選択も可能です。その場合、画像取得は必要時まで遅延できます。これらフェッチ失敗は無視されるため、順序は任意です。
-
registeredAccount、numRegisteredAccountsをそれぞれnullと0に設定。
-
accountをnullに設定。
-
accountsList内の各accについて:
-
accがprovider、globalObjectで自動再認証対象なら、registeredAccountにaccをセットしnumRegisteredAccountsを1増やす。
-
-
permission、disclosureTextShown、isAutoSelectedをfalseで初期化。
-
mediationが"
required"でなく、 requiresUserMediationがfalseかつnumRegisteredAccountsが1の場合:-
accountにregisteredAccountを、permissionにtrueをセットする。この処理時、ユーザーエージェントはユーザーに自動再認証されていることを示すUIを表示してもよい(MAY)。
-
isAutoSelectedにtrueをセットする。
-
-
それ以外の場合、mediationが"
silent"なら(failure, true)を返す。 -
それ以外で、accountsListのサイズが1の場合:
-
accountにaccountsList[0]をセット。
-
接続状態算出が account、provider、globalObjectでconnectedなら、 サインイン許可ダイアログを表示し、結果をpermissionにセット。 ユーザーエージェントはoptionsの
contextでダイアログをカスタマイズ可能。 -
それ以外の場合、サインアップ許可リクエストをaccount、config、provider、globalObjectで実行し、結果をpermissionにセット。disclosureTextShownもtrueに設定。
-
-
それ以外の場合:
-
アカウント選択を accountsListから実行し、結果をaccountに。
-
accountが失敗なら(failure, true)を返す。
-
接続状態算出がaccount、provider、globalObjectでconnectedならpermissionをtrueに設定。
-
それ以外の場合:
-
サインアップ許可リクエストをaccount、config、provider、globalObjectで実行し、結果をpermissionにセット。
-
disclosureTextShownをtrueに設定。
-
-
-
前ステップで生成されたダイアログがあれば、ユーザーの選択や許可が完了するまで待機。
-
Assert: accountはnullではない。
-
permissionがfalseなら(failure, true)を返す。
-
credentialをIDアサーション取得でaccountの
id、disclosureTextShown、isAutoSelected、provider、config、globalObjectで実行した結果とする。 -
credentialを返す。
2.3.5. 設定ファイルの取得
設定ファイルの取得アルゴリズムは、well-knownファイルと設定ファイルの両方をIDPから取得し、設定ファイルがwell-knownファイルで言及されているかを確認し、設定内容を返します。
IdentityProviderRequestOptions
providerとglobalObjectを受けて以下を実行。この処理はIdentityProviderAPIConfig
または失敗を返します。
-
configUrlが失敗なら失敗を返す。
-
Content Security Policy Level 3のconnect-srcディレクティブでconfigUrlに対してチェック。失敗した場合は失敗を返す。
-
configUrlがpotentially trustworthy URLでなければ失敗を返す。
-
rootUrlを新しいURLとする。
-
config、configInWellKnownの両方をnullに設定。
-
rpOriginをglobalObjectの関連Documentのoriginとする。
-
rpOriginがopaque originでなく、かつrootUrlのhostがrpOriginの登録可能ドメインと等しく、rootUrlのschemeがrpOriginのschemeと等しければ、configInWellKnownをtrueに設定。
注: ドメインCookieはサイト全体で有効なため、RPとIDPが同一サイトの場合、well-knownチェックをしてもプライバシー上の利点はありません。
-
それ以外の場合:
-
wellKnownRequestを新しいrequestで以下の通り作成:
- URL
-
rootUrl
- client
-
null
- window
-
"no-window"
- service-workers mode
-
"none"
- destination
-
"webidentity"
- origin
- header list
- referrer policy
-
"no-referrer"
- credentials mode
-
"omit"
- mode
-
"no-cors"
仕様ではすべてのrequestが
user-agent-no-corsで作成されるよう更新予定です。詳細はpull request参照。 -
fetch requestをwellKnownRequestとglobalObjectで実行し、processResponseConsumeBodyは次の手順でresponseとresponseBodyを処理:
-
jsonをresponseとresponseBodyでJSON fetchレスポンス抽出を実行した結果とする。
-
ECMAScript値からIDL値変換でjsonを
IdentityProviderWellKnown型discoveryに変換。 -
前2ステップで例外がthrowされた場合、またはdiscovery["
provider_urls"]のサイズが1より大きい場合、configInWellKnownをfalseに設定。 -
それ以外の場合、discovery["
provider_urls"][0]がproviderのconfigURLと一致ならconfigInWellKnownをtrue、それ以外はfalseに設定。
-
-
-
configRequestを新しいrequestで以下の通り作成:
- url
-
configUrl
- redirect mode
-
"error"
- client
-
null
- window
-
"no-window"
- service-workers mode
-
"none"
- destination
-
"webidentity"
- origin
- header list
- referrer policy
-
"no-referrer"
- credentials mode
-
"omit"
- mode
-
"no-cors"
仕様ではすべてのrequestが
user-agent-no-corsで作成されるよう更新予定です。詳細はpull request参照。 -
fetch requestをconfigRequestとglobalObjectで実行し、processResponseConsumeBodyは次の手順でresponseとresponseBodyを処理:
-
jsonをresponseとresponseBodyでJSON fetchレスポンス抽出を実行した結果とする。
-
ECMAScript値からIDL値変換でjsonを
IdentityProviderAPIConfig型のconfigに変換。 -
前2ステップで例外がthrowされた場合、configに失敗をセット。
-
config.
login_urlをprovider、config、globalObjectでmanifest URL算出した結果に設定。 -
config.
login_urlがnullなら失敗を返す。
-
-
configとconfigInWellKnownがセットされるまで待機。
-
configInWellKnownがtrueならconfigを返す。falseなら失敗を返す。
注: 2層ファイルシステムを採用することで、IDPが設定ファイルパスに情報をエンコードして訪問中のRPを容易に特定することを防ぎます。この問題は、well-knownファイルをIDPルートに必須とすることで解決します。設定ファイル自体は任意の場所に置けますが、ユーザーエージェントがwell-knownファイルで見つけなければ使用されません。これにより、IDPは実際の設定ファイルを任意パスに保管しつつ、ユーザーエージェントがRP名入りパス等によるフィンガープリンティングを防げます。詳細は§ 7.3.1 Manifest Fingerprinting参照。
dictionary {IdentityProviderWellKnown required sequence <USVString >provider_urls ; };dictionary {IdentityProviderIcon required USVString url ;unsigned long size ; };dictionary {IdentityProviderBranding USVString background_color ;USVString color ;sequence <IdentityProviderIcon >icons ;USVString name ; };dictionary {IdentityProviderAPIConfig required USVString accounts_endpoint ;required USVString client_metadata_endpoint ;required USVString id_assertion_endpoint ;required USVString ;login_url USVString disconnect_endpoint ;IdentityProviderBranding branding ; };
2.3.6. アカウントの取得
アカウントの取得アルゴリズムはaccountsエンドポイントを取得し、ユーザーがログインしているIDPアカウントのリストを判別します。これにより、後でユーザーエージェントがFedCM UIをユーザーに表示できます。
IdentityProviderAPIConfig
config、IdentityProviderRequestOptions
provider、globalObjectを受けて以下を実行。この処理はIdentityProviderAccountListを返します。
-
accountsUrlをprovider、config["
accounts_endpoint"]、globalObjectでmanifest URL算出した結果とする。 -
accountsUrlが失敗の場合は空リストを返す。
-
requestを新しいrequestで以下の通り作成:
- url
-
accountsUrl
- redirect mode
-
"error"
- client
-
null
- window
-
"no-window"
- service-workers mode
-
"none"
- destination
-
"webidentity"
- origin
- header list
- referrer policy
-
"no-referrer"
- credentials mode
-
"include"
- mode
-
"no-cors"
このアルゴリズムでのcredentialed fetchは、ユーザーが許可する前にタイミング攻撃でユーザーIDが漏れる可能性があります。調査内容はこちら。
仕様ではすべてのrequestが
user-agent-no-corsで作成されるよう更新予定です。詳細はpull request参照。 -
accountsListをnullに設定。
-
fetch requestをrequestとglobalObjectで実行し、processResponseConsumeBodyは次の手順でresponseとresponseBodyを処理:
-
jsonをresponseとresponseBodyでJSON fetchレスポンス抽出を実行した結果とする。
-
ECMAScript値からIDL値変換でjsonを
IdentityProviderAccountList型のaccountsListに変換。 -
前2ステップで例外がthrowされた場合、accountsListに失敗をセット。
ここで返されるaccountsリストは重複id検証が必要です。詳細はこちら参照。
-
-
accountsListがセットされるまで待機。
-
accountsListを返す。
dictionary {IdentityProviderAccount required USVString id ;required USVString name ;required USVString USVString given_name ;USVString picture ;sequence <USVString >approved_clients ;sequence <DOMString >login_hints ;sequence <DOMString >domain_hints ; };dictionary {IdentityProviderAccountList sequence <IdentityProviderAccount >; };accounts
IdentityProviderAccount
account、globalObjectを受けて以下を実行:
-
pictureUrlをaccount["
picture"]とglobalObjectでparse urlした結果とする。 -
pictureUrlが失敗なら手順を中止。ユーザーエージェントはプレースホルダー画像を利用可。
-
pictureRequestを新しいrequestで以下の通り作成:
- url
-
pictureUrl
- client
-
null
- window
-
"no-window"
- service-workers mode
-
"none"
- destination
-
"image"
- origin
- referrer policy
-
"no-referrer"
- credentials mode
-
"omit"
- mode
-
"no-cors"
仕様ではすべてのrequestが
user-agent-no-corsで作成されるよう更新予定です。詳細はpull request参照。 -
fetch requestをpictureRequestとglobalObjectで実行し、processResponseConsumeBodyは次の手順でresponseとresponseBodyを処理:
-
responseBodyがnullまたは失敗なら、ユーザーエージェントは任意のプレースホルダー画像を選択しaccountに関連付けてもよい。
-
それ以外の場合、responseBodyを画像にデコードし、成功した場合はaccountに関連付ける。これにより、ユーザーエージェントはダイアログ表示時にデコード済み画像を利用できる。
-
2.3.7. IDアサーションの取得
IDアサーションの取得アルゴリズムは、ユーザーが特定のIDPアカウントでFedCMの利用を許可した後に呼び出されます。IDアサーションエンドポイントからトークンを取得し、それをRPに提供します。
USVString
accountId、boolean disclosureTextShown、boolean isAutoSelected、IdentityProviderRequestOptions
provider、IdentityProviderAPIConfig
config、globalObjectを受けて以下を実行。この処理はIdentityCredential
または失敗を返す。
-
tokenUrlをprovider、config["
id_assertion_endpoint"]、globalObjectでmanifest URL算出した結果とする。 -
tokenUrlが失敗なら失敗を返す。
-
requestBodyをurlencoded serializerで以下のリストを渡して作成:
-
requestを新しいrequestで以下の通り作成:
- url
-
tokenUrl
- method
-
"POST"
- body
-
UTF-8 encodeされたrequestBody
- redirect mode
-
"error"
- client
-
null
- window
-
"no-window"
- service-workers mode
-
"none"
- destination
-
"webidentity"
- origin
- header list
-
listに、header(nameは
Accept、valueはapplication/x-www-form-urlencoded)を1つだけ含める - credentials mode
-
"include"
- mode
-
"cors"
-
credentialをnullとする。
-
fetch requestをrequestとglobalObjectで実行し、processResponseConsumeBodyは次の手順でresponseとresponseBodyを処理:
-
jsonをresponseとresponseBodyでJSON fetchレスポンス抽出した結果とする。
-
ECMAScript値からIDL値変換でjsonを
IdentityProviderToken型のtokenに変換。 -
前2ステップで例外がthrowされた場合、credentialに失敗をセットしreturn。
-
credentialを新しい
IdentityCredentialとして、globalObjectのrealmを渡して生成。 -
credentialの
tokenにtokenをセット。 -
credentialの
isAutoSelectedにisAutoSelectedをセット。
-
-
credentialがセットされるまで待機。
-
credentialを返す。
dictionary {IdentityProviderToken required USVString token ; };
2.3.8. サインアップ許可のリクエスト
IdentityProviderAccount
または失敗を返す。
-
Assert accountsListのサイズが1より大きい。
-
accountsListから選択肢を表示するアカウントチューザーを表示する。
-
ユーザーがアカウントチューザーから手動で選択した
IdentityProviderAccountをaccountとし、選択されなければ失敗。 -
accountを返す。
サインアップ許可リクエストアルゴリズムは、client metadataエンドポイントを取得し、ユーザーが指定アカウントの利用を許可するまで待機し、許可したかどうかを返します。
IdentityProviderAccount
account、IdentityProviderAPIConfig
config、IdentityProviderRequestOptions
provider、globalObjectを受けて以下を実行。Booleanを返す。
-
Assert: これらの手順は並列で動作している。
-
metadataをclient metadata取得でconfig、provider、globalObjectで得る。
-
ユーザーにアカウント作成の明示的な意思を求めるダイアログを表示する。ユーザーエージェントはUIスタイル選択に
IdentityProviderBrandingを利用してもよい。加えて:-
metadataが失敗でなく、metadata["
privacy_policy_url"]が定義され、providerのclientIdがaccount["approved_clients"]リストに含まれていない場合、ユーザーエージェントはmetadata["privacy_policy_url"]リンクを表示しなければならない。 -
metadataが失敗でなく、metadata["
terms_of_service_url"]が定義され、providerのclientIdがaccount["approved_clients"]リストに含まれていない場合、ユーザーエージェントはmetadata["terms_of_service_url"]リンクを表示しなければならない。 -
ユーザーエージェントは表示ダイアログのカスタマイズに
contextを利用してもよい。
-
-
ユーザーが許可しなければfalseを返す。
-
RPとIdPアカウント間の接続作成をprovider、account、globalObjectで実行。
-
trueを返す。
IdentityProviderAPIConfig
config、IdentityProviderRequestOptions
providerを受けて以下を実行。この処理はIdentityProviderClientMetadata
または失敗を返す。
-
clientMetadataUrlをprovider、config["
client_metadata_endpoint"]、globalObjectでmanifest URL算出した結果とする。 -
clientMetadataUrlが失敗なら失敗を返す。
-
requestを新しいrequestで以下の通り作成:
- url
-
clientMetadataUrl
- redirect mode
-
"error"
- client
-
null
- window
-
"no-window"
- service-workers mode
-
"none"
- destination
-
"webidentity"
- origin
- header list
- credentials mode
-
"omit"
- mode
-
"no-cors"
仕様ではすべてのrequestが
user-agent-no-corsで作成されるよう更新予定です。詳細はpull request参照。 -
metadataをnullに設定。
-
fetch requestをrequestとglobalObjectで実行し、processResponseConsumeBodyは次の手順でresponseとresponseBodyを処理:
-
jsonをresponseとresponseBodyでJSON fetchレスポンス抽出した結果とする。
-
ECMAScript値からIDL値変換でjsonを
IdentityProviderClientMetadata型のmetadataに変換。 -
前2ステップで例外がthrowされた場合、metadataに失敗をセット。
-
-
metadataがセットされるまで待機。
-
metadataを返す。
dictionary {IdentityProviderClientMetadata USVString privacy_policy_url ;USVString terms_of_service_url ; };
2.3.9. 補助アルゴリズム
以下の補助アルゴリズムはFedCMフローの中で使用されます。
USVString
stringUrl、globalObject、省略可能なbaseUrl(デフォルトはnull)を受けて以下を実行。この処理はURLまたは失敗を返す。
-
configUrlをnullに設定。
-
グローバルタスクをキューし、DOM操作タスクソースでglobalObjectに対し、configUrlにurl parserをstringUrlとbaseUrlで実行した結果をセット。
注: url parserはタスク内で実行する必要があるため、並列実行ではなくタスクをキューします。
-
configUrlがセットされるまで待機。
-
configUrlを返す。
-
グローバルタスクをキューし、ネットワークタスクソースにglobalObjectを渡して以下を実行:
-
fetch request(processResponseConsumeBodyをprocessResponseConsumeBodyにセット)を行う。
-
注: fetchはタスク内で実行する必要があるため、並列実行ではなくタスクをキューします。
IdentityProviderRequestOptions
provider、string manifestString、globalObjectを受けて以下を実行。この処理はURLまたは失敗を返す。
-
manifestUrlをparse urlでmanifestString(相対URL)、globalObject、configUrl(baseUrl)を渡して得る。
-
manifestUrlがセットされるまで待機。
注: manifest stringは絶対URLでも相対URLでも渡せます。
-
manifestUrlが失敗なら失敗を返す。
-
manifestUrlがconfigUrlと同一オリジンでなければ失敗を返す。
-
manifestUrlがpotentially trustworthy URLでなければ失敗を返す。
-
manifestUrlを返す。
-
Assert: この手順はネットワークタスクソースで実行している。
-
responseがネットワークエラーまたはstatusがok statusでなければ、"
NetworkError"DOMExceptionをthrowする。 -
mimeTypeをMIME TYPE抽出でresponseのheader listから得る。
-
mimeTypeが失敗またはJSON MIME Typeでなければ、"
NetworkError"DOMExceptionをthrowする。 -
jsonをparse JSON bytes to JavaScript valueでresponseBodyを渡して得る。
-
jsonがパース例外なら、"
NetworkError"DOMExceptionをthrowする。 -
jsonを返す。
IdentityProviderAPIConfig
config、IdentityProviderConfig
provider、globalObjectを受けて以下を実行。この処理はsuccessまたはfailureを返す。
-
Assert: この手順は並列で動作している。
-
loginUrlをnullとする。
-
グローバルタスクをキューし、DOM操作タスクソースでglobalObjectに対し、loginUrlにurl parserをconfig.
login_urlで実行した結果をセット。 -
loginUrlがnullでなくなるまで待機。
-
Assert: loginUrlは失敗でない(ユーザーエージェントはconfig.
login_urlが有効なURLであることを事前に確認済み)。 -
queryListを新しいlistとする。
-
providerの
loginHintが空でなければ、("login_hint",loginHint)をappendしてqueryListに加える。 -
providerの
domainHintが空でなければ、("domain_hint",domainHint)をappendしてqueryListに加える。 -
queryListが空でない場合:
-
queryParametersをurlencoded serializerでqueryListを渡して得る。
-
loginUrlのqueryがnullまたは空でなければ、queryParametersの先頭に"&"を追加。
-
queryParametersをloginUrlのqueryに追加。
-
-
新しいトップレベルtraversableを作成し、loginUrlで表示する。
-
ユーザーエージェントはbrowsing context featuresのセットアップやその他の実装定義の方法でこのtraversableの表示を調整してもよい。
-
以下いずれかになるまで待機:
-
ユーザーがbrowsing contextを閉じた場合:failureを返す。
-
この新しいtraversableの文脈で
IdentityProvider.closeが呼び出された場合:-
traversableを閉じる。
-
loginStatusをget the login statusで
login_urlのoriginを渡して取得。注: IDPログインフローでは、JavaScriptやHTTPヘッダーAPIによってこの値がlogged-inに設定される場合があります。別のbrowsing contextで変更されている可能性もあります。
-
loginStatusがlogged-inならsuccessを返す。
-
それ以外の場合はfailureを返す。
-
-
2.4. IdentityProviderインターフェース
この仕様はIdentityUserInfo
辞書およびIdentityProvider
インターフェースを導入します:
dictionary {IdentityUserInfo USVString ;USVString ;name USVString ;givenName USVString ; }; [picture Exposed =Window ,SecureContext ]interface {IdentityProvider static undefined ();close static Promise <sequence <IdentityUserInfo >>(getUserInfo IdentityProviderConfig ); };config
決定 IdentityProvider
が
getUserInfo()
メソッドの正しい場所かどうかを検討する。
close
関数は、ログインフローが完了したことをブラウザに通知するために用意されています。この関数がヘッダーとは別に存在する理由は、ユーザーがすでにログインしている場合でもログインフローがまだ終わっていない場合があるためです。例えば、IDPがユーザーに電話番号の確認を促したいことがあります。こうしたフローに対応するため、IDPはフローが完全に終わった時点でclose
を呼ぶ必要があります。
詳細はIDPログインダイアログ表示アルゴリズムを参照してください。
IdentityUserInfo
はユーザーのアカウント情報を表します。この情報は、ユーザーがすでにFedCM APIを使ってRPにログインした後にIDPに公開されます。つまり、接続済みアカウントセットが(三つ組:RP, IDP,
account)を含む場合に公開されます。この情報はaccounts endpointで受け取った内容と一致します。IDPは、自身のconfigURLのoriginに一致するiframeからgetUserInfo()
静的メソッドを呼び出すことでこの情報を取得できます。
const userInfo= await IdentityProvider. getUserInfo({ configUrl: "https://idp.example/fedcm.json" , clientId: "client1234" }); if ( userInfo. length> 0 ) { // 返されたアカウントの表示方法はIDPが決定します。 const name= userInfo[ 0 ]. name; const givenName= userInfo[ 0 ]. givenName; const displayName= givenName? givenName: name; const picture= userInfo[ 0 ]. picture; const email= userInfo[ 0 ]. email; }
getUserInfo()
メソッドをIdentityProviderConfig
providerで呼び出したとき、以下の手順を実行する:
-
globalObjectを現在のグローバルオブジェクトとする。
-
documentをglobalObjectの関連付けられたDocumentとする。
-
documentがallowed to useのidentity-credentials-get ポリシー制御機能の利用が許可されていない場合、"
NotAllowedError"DOMExceptionをthrowする。 -
接続済みアカウントセットが、含む値としてconnected account keyの算出でaccount、provider、globalObjectを渡して得た値がなければ、reject promiseを"
NetworkError"DOMExceptionでrejectする。 このチェックは接続済みアカウントセットをイテレートするか、高速化のため別データ構造を保持してもよい。 -
configUrlが失敗なら"
InvalidStateError"DOMExceptionをthrowする。 -
documentのoriginがconfigUrlのoriginと同一オリジンでなければ、"
InvalidStateError"DOMExceptionをthrowする。 -
Content Security Policy Level 3のconnect-srcディレクティブでconfigUrlに対してチェック。失敗した場合は"
NetworkError"DOMExceptionをthrowする。 -
globalObjectのnavigableがトップレベルtraversableの場合、"
NetworkError"DOMExceptionをthrowする。 -
ユーザーがglobalObjectのnavigableのトップレベルtraversableでFedCM APIを無効にしている場合、"
NetworkError"DOMExceptionをthrowする。 -
promiseを新しい
Promiseとする。 -
以下の手順を並列で実行する:
-
configを設定ファイルの取得でprovider、globalObjectで得る。
-
configが失敗なら、reject promiseを新しい"
NetworkError"DOMExceptionでrejectする。 -
accountsListをアカウントの取得でconfig、provider、globalObjectで得る。
-
hasAccountEligibleForAutoReauthenticationをfalseとする。
-
accountsList内の各accountについて:
-
account["
approved_clients"]が空でなく、かつproviderのclientIdを含まない場合はcontinue。注: これによりIDPはアカウントが再度アクセス可能かどうかを上書きできます。例えばユーザーが外部でアカウントを切断した場合などに有用です。
-
accountがprovider、globalObjectで自動再認証対象ならhasAccountEligibleForAutoReauthenticationをtrueにする。
-
-
hasAccountEligibleForAutoReauthenticationがfalseなら、reject promiseを新しい "
NetworkError"DOMExceptionでrejectする。 -
userInfoListを新しいlistとする。
-
accountsList内の各accountについて:
-
appendで以下の値で
IdentityUserInfoをuserInfoListに追加:
-
-
3. アイデンティティプロバイダー HTTP API
このセクションは規範的ではありません。
IDPは一連のHTTPエンドポイントを公開します:
-
§ 3.1 well-knownファイル(マニフェストへの参照)
-
合意済みの場所にある§ 3.2 設定ファイル(他エンドポイントへの参照)
-
§ 3.4 クライアントメタデータエンドポイント
-
§ 3.6 切断エンドポイント(
disconnectをサポートする場合)
FedCM APIは、サイトがブラウザに対していくつかのネットワークリクエストを実行させる機能を導入します。ブラウザは、これらのリクエストが(攻撃者がIDPを偽装している場合でも)FedCMを使ってユーザーが追跡されることがないように慎重に実行する必要があります。下記の表は実行されるネットワークリクエストの情報を示しています:
| エンドポイント | Cookie | client_id | オリジン |
| manifests | なし | なし | なし |
| accounts_endpoint | あり | なし | なし |
| client_metadata_endpoint | なし | あり | あり |
| id_assertion_endpoint | あり | あり | あり |
| disconnect_endpoint | あり | あり | あり |
3.1. well-knownファイル
注: ブラウザはwell-knownファイルを使い、§ 7.3.1 マニフェストフィンガープリンティングを防ぎます。
IDPは、所定の場所(".well-known"パスの "web-identity"ファイル)にwell-knownファイルを公開します。
well-knownファイルは、設定ファイル取得アルゴリズムで取得されます:
(a) Cookieなしで、
(b) Sec-Fetch-Destヘッダーがwebidentityにセットされ、
(c) RP情報をOriginやRefererヘッダーで漏らさずに取得します。
例:
GET /.well-known/web-identity HTTP / 1.1 Host : idp.example Accept : application/json Sec-Fetch-Dest : webidentity
このファイルはIdentityProviderWellKnown
JSONオブジェクトとしてパースされます。
IdentityProviderWellKnown
JSONオブジェクトの意味:
provider_urls(必須), 型: sequence<USVString>-
有効な§ 3.2 設定ファイルへのURLリスト。
3.2. 設定ファイル
設定ファイルは、IDPが提供する他エンドポイントへの発見手段です。
(a) Cookieなしで、
(b) Sec-Fetch-Destヘッダーがwebidentityにセットされ、
(c) RP情報をOriginやRefererヘッダーで漏らさずに取得し、
(d) HTTPリダイレクトを追従しない。
例:
レスポンスボディは、例外なくIdentityProviderAPIConfig
へ変換できるJSONオブジェクトでなければなりません。
IdentityProviderAPIConfig
オブジェクトの各メンバーの意味:
accounts_endpoint, 型: USVString-
§ 3.3 アカウントエンドポイントAPIに準拠するHTTP APIへのURL。
client_metadata_endpoint, 型: USVString-
§ 3.4 クライアントメタデータAPIに準拠するHTTP APIへのURL。
id_assertion_endpoint, 型: USVString-
§ 3.5 IDアサーションエンドポイントAPIに準拠するHTTP APIへのURL。
disconnect_endpoint, 型: USVString-
§ 3.6 切断エンドポイントAPIに準拠するHTTP APIへのURL。
branding, 型: IdentityProviderBranding-
IdentityProviderBrandingオプションセット。
IdentityProviderBranding
により、IDPはブランド表現の希望を示すことができ、ユーザーエージェントはこれを許可プロンプトのカスタマイズに利用可能です。
注: ブランド表現はUI構造に依存せず抽象的に設計されており、ユーザーエージェント毎に異なるUI体験を提供でき、時間の経過とともに独立して進化できます。
各メンバーの意味:
background_color, 型: USVStringcolor, 型: USVStringicons, 型: sequence<IdentityProviderIcon>-
IdentityProviderIconオブジェクトのリスト。 name, 型: USVString-
IDPのユーザーに分かりやすい名称。
注: ブランド表現はUI構造に依存しない抽象設計で、ユーザーエージェント毎に多様なUIを提供し、独立進化できます。
IdentityProviderIcon
の各メンバーの意味:
url, 型: USVString-
アイコン画像のURL(正方形・単一解像度であること。複数解像度.ico不可)。アイコンはmaskable仕様準拠。
size, 型: unsigned long-
正方形アイコンの幅/高さ。SVG等ベクター形式なら省略可。
注: ユーザーエージェントは、提供されたアイコンに正方形領域を割り当てます。正方形でない場合は表示しない・切り抜き・変換等の選択肢もあります。
色はCSS<color> 構文のサブセットで、<hex-color>、hsl()、rgb()、<named-color> を指定できます。
例:
{ "accounts_endpoint" : "/accounts" , "client_metadata_endpoint" : "/metadata" , "id_assertion_endpoint" : "/assertion" , "disconnect_endpoint" : "/disconnect" , "branding" : { "background_color" : "green" , "color" : "#FFEEAA" , "icons" : [{ "url" : "https://idp.example/icon.ico" , "size" : 25 }], "name" : "IDP Example" } }
3.3. アカウントエンドポイント
アカウントエンドポイント は、ユーザーがIDPで持っているアカウント一覧を提供します。
アカウントエンドポイント はアカウントの取得アルゴリズムで取得されます:
(a) IDP Cookieありで、
(b) Sec-Fetch-Destヘッダーがwebidentityにセットされ、
(c) RP情報をOriginやRefererヘッダーで漏らさずに、
(d) HTTPリダイレクトを追従しない。
例:
GET /accounts_list HTTP / 1.1 Host : idp.example Accept : application/json Cookie : 0x23223 Sec-Fetch-Dest : webidentity
レスポンスボディは、例外なくIdentityProviderAccountList型へ変換できるJSONオブジェクトでなければなりません。
各IdentityProviderAccount
のメンバー意味:
id, 型: USVString-
アカウントの一意識別子。
name, 型: USVString-
ユーザーの氏名(フルネーム)。
email, 型: USVString-
ユーザーのメールアドレス。
given_name, 型: USVString-
ユーザーの名。
picture, 型: USVString-
アカウント画像のURL。
approved_clients, 型: sequence<USVString>-
このアカウントがすでに登録済みのRP(
clientIdで照合)リスト。 サインアップ許可リクエストで、プライバシーポリシーや利用規約の表示制御に使われます。 login_hints, 型: sequence<DOMString>-
アカウントに一致するすべてのログインヒントの文字列リスト。RPは
loginHintを使い、指定値に一致するアカウントのみを表示させることができます。 domain_hints, 型: sequence<DOMString>-
アカウントに一致するすべてのドメインヒントの文字列リスト。RPは
domainHintを使い、指定値またはドメインヒントを含むアカウントのみ表示できます。
例:
{ "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" : [ "john_doe" ], "domain_hints" : [ "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" : [ "email=johhny@idp.example" , "id=5678" ], "domain_hints" : [ "idp.example" ], }] }
ユーザーが未ログインの場合のIDP APIレスポンスの明確化
3.4. クライアントメタデータ
クライアントメタデータエンドポイントは、RPのメタデータを提供します。
クライアントメタデータエンドポイントはクライアントメタデータ取得アルゴリズムで取得されます:
(a) Cookieなしで、
(b) Sec-Fetch-Destヘッダーがwebidentityにセットされ、
(c) RPのオリジンをOriginヘッダーに入れて、
(d) HTTPリダイレクトを追従しない。
ユーザーエージェントはclient_idも渡します。
例:
GET /client_medata?client_id=1234 HTTP / 1.1 Host : idp.example Origin : https://rp.example/ Accept : application/json Sec-Fetch-Dest : webidentity
レスポンスボディは、例外なくIdentityProviderClientMetadata型へ変換できるJSONオブジェクトでなければなりません。
IdentityProviderClientMetadata
オブジェクトのメンバー意味:
privacy_policy_url, 型: USVString-
RPのプライバシーポリシーへのリンク。
terms_of_service_url, 型: USVString-
RPの利用規約へのリンク。
例:
{ "privacy_policy_url" : "https://rp.example/clientmetadata/privacy_policy.html" , "terms_of_service_url" : "https://rp.example/clientmetadata/terms_of_service.html" }
3.5. IDアサーションエンドポイント
IDアサーションエンドポイントは、ユーザーに関する署名付きアサーションを含む新しいトークンを生成します。
IDアサーションエンドポイントはIDアサーション取得アルゴリズムで取得されます:
(a) POSTリクエストとして、
(b) IDP Cookieありで、
(c) RPのオリジンをOriginヘッダーに入れ、
(d) Sec-Fetch-Destヘッダーがwebidentityにセットされ、
(e) HTTPリダイレクトを追従しない。
リクエストボディ(application/x-www-form-urlencoded)には以下のパラメータが含まれます:
client_idnonce-
リクエストnonce
account_id-
選択されたアカウント識別子。
disclosure_text_shown-
ユーザーエージェントがユーザーに、IDPがRPへどんな情報(例:"idp.exampleはあなたの氏名・メールアドレス...をrp.exampleに共有します"など)を共有するか明示したかどうか(新規ユーザー用サインアップ許可リクエストで利用)。利用規約・プライバシーポリシー表示保証としてIDPへ通知されます。
例:
POST /fedcm_assertion_endpoint HTTP / 1.1 Host : 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
clientIdで表されていることを必ず確認しなければなりません。
clientId
はIDP固有なので、ユーザーエージェントではこの確認はできません。
レスポンスボディは、例外なくIdentityProviderToken型へ変換できるJSONオブジェクトでなければなりません。
各IdentityProviderToken
のメンバー意味:
token, 型: USVString-
生成されたトークン。
token
の内容はユーザーエージェントにとって不透明であり、IDPがログイン促進のためにRPへ渡したい任意の情報を含めることができます。したがって、RPがトークン検証アルゴリズムに従い検証責任を持ちます。例としてはOIDC Connect Core
§ IDTokenValidation参照。
注: IDPにとっては、ポータブルなアカウントの扱いも検討事項です。ポータビリティはIDPに一任され、IDPは様々な手段(例:OIDC Account Porting)から選択できます。
例:
3.6. 切断エンドポイント
切断エンドポイントは、RPとIDPアカウント間で作成されたフェデレーションログイン接続を切断し、アカウントのid
を返すことで、ユーザーエージェントが接続済みアカウントセットから削除できるようにします。
切断エンドポイントはdisconnect
メソッド呼び出し時に取得されます:
(a) POSTリクエストとして、
(b) IDP Cookieありで、
(c) RPのオリジンをOriginヘッダーに入れ、
(d) Sec-Fetch-Destヘッダーがwebidentityにセットされ、
(e) HTTPリダイレクトを追従しない、
(f) "cors"モードで。
リクエストボディ(application/x-www-form-urlencoded)には以下が含まれます:
例:
POST /fedcm_disconnect_endpoint HTTP / 1.1 Host : idp.example Origin : https://rp.example/ Content-Type : application/x-www-form-urlencoded Cookie : 0x23223 Sec-Fetch-Dest : webidentity client_id=client1234&account_hint=hint12
切断が失敗した場合、IDPはエラー応答可能です。成功時は、レスポンスボディが例外なくDisconnectedAccount型へ変換できるJSONオブジェクトでなければなりません。
account_id, 型: USVString-
切断が成功したアカウントの
id
IDPはaccount_id
を必ず返さなければなりません。これはaccount_hint
と異なる場合があり、IDはユーザーエージェントが接続済みアカウントセットからアカウントを切断するために必要です。IDPがエラーを返す場合や、ユーザーエージェントがIDPの返したIDのアカウントを見つけられない場合、関連する(RP, IDP)に紐付くすべてのアカウントが接続済みアカウントセットから削除されます。
4. Permissions Policy統合
FedCMは、文字列"identity-credentials-get"で識別されるポリシー制御機能を定義します。
そのデフォルト許可リストは"self"です。
Documentの
permissions policyは、その文書でBrowser APIを使ってクレデンシャルオブジェクトを取得できるかどうかを決定します。
navigator.credentials.get({identity:..., ...})
を、その文書がidentity-credentials-get
機能の利用を許可されていない場合に呼び出すと、
promise rejected with "NotAllowedError"
DOMExceptionになります。
この制限は、Permissions Policyで説明されている仕組みで制御できます。
注: Credential Management Level
1で規定されるアルゴリズムが、実際のpermissions policy評価を行います。これは評価がcurrent settings objectへのアクセス時に必要だからです。本仕様が拡張する内部メソッドは並列で呼び出されるため、こうしたアクセス権を持ちません。並列呼び出しは
CredentialsContainerの
Request a Credential抽象操作によります。
5. ユーザーエージェント自動化
ユーザーエージェントの自動化やウェブサイトのテストのために、本ドキュメントはFedCMダイアログ操作用のWebDriverの拡張コマンドを定義します。
5.1. 拡張機能
下記の拡張コマンドの利用可能性を通知するため、新しい拡張機能が定義されます。
| 機能 | キー | 値型 | 説明 |
|---|---|---|---|
| Federated Credential Management Support | "fedcm:accounts"
| boolean | エンドポイントノードが、全てのFederated Credential Managementコマンドをサポートしているか示す。 |
機能検証時に、拡張固有のサブステップとして"fedcm:accounts"のvalueを検証する手順:
-
valueがbooleanでなければ、WebDriverエラー(error code:invalid argument)を返す。 -
それ以外の場合は
deserializedにvalueをセット。
機能マッチング時に、"fedcm:accounts"のvalueをマッチさせる拡張手順:
-
valueがtrueで、エンドポイントノードがFederated Credential Managementコマンドを一つもサポートしていなければ、マッチは失敗。 -
それ以外はマッチ成功。
5.2. ダイアログキャンセル
| HTTPメソッド | URIテンプレート |
|---|---|
| POST | /session/{session id}/fedcm/canceldialog
|
-
FedCMダイアログが現在開いていなければ、WebDriverエラー(error code:no such alert)を返す。
-
ダイアログを閉じ、ユーザーがアカウント選択せずキャンセルしたものとしてIdentityCredential作成アルゴリズムを継続。
-
success(データ
null)を返す。
5.3. アカウント選択
| HTTPメソッド | URIテンプレート |
|---|---|
| POST | /session/{session id}/fedcm/selectaccount
|
-
parametersがJSONObjectでなければ、WebDriverエラー(error code:invalid argument)を返す。
-
FedCMダイアログが現在開いていなければ、WebDriverエラー(error code:no such alert)を返す。
-
accountIndexをparametersから
"accountIndex"でプロパティ取得で得る。 -
accountIndexが
undefinedまたは0未満、またはユーザーが選択可能なアカウント数以上なら、WebDriverエラー(error code:invalid argument)を返す。 -
ダイアログを閉じ、accountIndexで指定されたアカウントをユーザーが選択し、必要に応じてサインアップ許可したものとしてIdentityCredential作成アルゴリズムを継続。
-
success(データ
null)を返す。
5.4. ダイアログボタンをクリック
| HTTPメソッド | URIテンプレート |
|---|---|
| POST | /session/{session id}/fedcm/clickdialogbutton
|
-
parametersがJSONObjectでなければ、WebDriverエラー(error code:invalid argument)を返す。
-
dialogButtonをparametersから
"dialogButton"でプロパティ取得で得る。 -
dialogButtonが文字列"
ConfirmIdpLoginContinue"でなければ、WebDriverエラー(error code:invalid argument)を返す。 -
FedCMダイアログが現在開いていないか、ダイアログがIDPログイン確認ダイアログでなければ、WebDriverエラー(error code:no such alert)を返す。
-
ユーザーがIDPログイン確認ダイアログで「続行」ボタンをクリックしたものとしてログインフローを開始する。
-
success(データ
null)を返す。
5.5. アカウントリスト
| HTTPメソッド | URIテンプレート |
|---|---|
| GET | /session/{session id}/fedcm/accountlist
|
以下はリモートエンド手順です:
-
FedCMダイアログが現在開いていない場合、WebDriverエラー(error code: no such alert)を返す。
-
accountsを、現在のフローでユーザーが選択できる(またはできた)アカウントのリストとする。
-
listを空リストとする。
-
accounts内の各accountについて:
-
accountStateを、accountとそのIDPの
IdentityProviderRequestOptionsを使って接続状態算出アルゴリズムで得る。 -
appendで、以下のプロパティを持つ辞書をlistに追加:
-
accountIdにはアカウントのidをセット -
emailにはアカウントのemailをセット -
nameにはアカウントのnameをセット -
givenNameにはアカウントのgiven_name(あれば)をセット -
pictureUrlにはアカウントのpicture(あれば)をセット -
idpConfigUrlにはこのアカウントが所属するIDPのconfigURLをセット -
loginStateはaccountStateがdisconnectedなら"SignUp"、それ以外は"SignIn" -
termsOfServiceUrlはloginStateが"SignUp"かつ値があればterms_of_service_url、そうでなければundefined -
privacyPolicyUrlはloginStateが"SignUp"かつ値があればprivacy_policy_url、そうでなければundefined
-
-
-
データlistでsuccessを返す。
5.6. タイトル取得
| HTTPメソッド | URIテンプレート |
|---|---|
| GET | /session/{session id}/fedcm/gettitle
|
注: このコマンドは自動化でcontext apiが正しく適用されたか検証できます。
-
FedCMダイアログが現在開いていない場合、WebDriverエラー(error code: no such alert)を返す。
-
dataを、以下のプロパティを持つオブジェクトの辞書とする:
-
title:開いているダイアログのタイトル -
subtitle:開いているダイアログのサブタイトル(あれば)
-
-
データdataでsuccessを返す。
5.7. ダイアログ種別取得
| HTTPメソッド | URIテンプレート |
|---|---|
| GET | /session/{session id}/fedcm/getdialogtype
|
-
FedCMダイアログが現在開いていない場合、WebDriverエラー(error code: no such alert)を返す。
-
typeを以下の値でセット:ユーザーが自動再認証されている場合は"
AutoReauthn"、アカウント選択ダイアログなら"AccountChooser"、IDPログイン確認ダイアログなら"ConfirmIdpLogin"。 -
データtypeでsuccessを返す。
5.8. 遅延有効化設定
| HTTPメソッド | URIテンプレート |
|---|---|
| POST | /session/{session id}/fedcm/setdelayenabled
|
-
parametersがJSONObjectでなければ、WebDriverエラー(error code: invalid argument)を返す。
-
enabledをparametersから
"enabled"でプロパティ取得で得る。 -
enabledが
undefinedまたはbooleanでなければ、WebDriverエラー(error code: invalid argument)を返す。 -
enabledがfalseならpromise拒否遅延を無効化、それ以外は再有効化。
-
success(データ
null)を返す。
5.9. クールダウンリセット
| HTTPメソッド | URIテンプレート |
|---|---|
| POST | /session/{session id}/fedcm/resetcooldown
|
-
ユーザーエージェントがクールダウン遅延(ダイアログを閉じた後APIが一定時間無効化される)を用いている場合、このコマンドでクールダウンをリセットし、次のFedCM呼び出しを成功可能にする。
-
success(データ
null)を返す。
6. セキュリティ
このセクションではFedCM APIのセキュリティ考慮事項をいくつか説明します。プライバシーに関する考慮事項は§ 7 Privacyに別途記載しています。
6.1. Content Security Policy
FedCM APIによる最初のfetchは公開マニフェストリストと設定ファイルです。悪意あるスクリプトがRPで実行され、FedCM APIを使って悪意あるIDPへAPI呼び出しを行うことを考えます(このIDPはRPが信頼しないもの)。もし呼び出しが成功すれば、RP上に悪意あるIDPのサインインUIが表示され、ユーザーを騙す可能性があります。これを防ぐ仕組みがContent Security Policy Level 3チェックです。悪意あるIDPのマニフェストのオリジンがRPのContent Security Policy Level 3のallowlistに含まれなければ、FedCM UIは表示されません。その後のfetchはすべて設定ファイルの同一オリジン、または内容に依存するため追加のチェックは不要です。
非同一オリジンfetch(例:ブランドアイコン)にはCSPチェックはありません。これはmanifestから直接指定され、ユーザーエージェントが画像を描画するため、RPサイトに影響したりRPが画像内容を検査することはできません。
6.2. Sec-Fetch-Destヘッダー
FedCM APIはIDP上に複数の非静的エンドポイントを導入するため、XSS攻撃から守る必要があります。FedCM APIはSec-Fetch-Destヘッダー(禁止リクエストヘッダー)に新しい値webidentityを導入します。この値はウェブサイトが勝手にセットできないため、IDPはFedCMブラウザからのリクエストであることを確認できます。IDPはこのヘッダー値をcredentialedリクエストで必ずチェックし、FedCM
APIによる正当なリクエストか確かめます。悪意あるサイトはFedCM APIを乱用できず、新エンドポイントの保護は十分です。
6.3. CORSヘッダー
FedCM APIはIDアサーションエンドポイントのレスポンスをRPに共有できるため、IDPはこの共有に明示的同意する必要があります。これはこのエンドポイントfetch時に"cors"モードを使うことで実現されます。Sec-Fetch-Destを無視するサーバーでもCORSは無視できず、CORSなしならfetchは失敗します。
6.4. ブラウザUIなりすまし
FedCM APIは新たな(信頼された)ユーザーエージェントUIを導入し、ユーザーエージェントはこのUIをページ内容の上に全面表示する場合があります(このUI表示はページがFedCM呼び出しを行った結果)。悪意あるサイトがFedCM UIを模倣し、ユーザーに信頼されたブラウザUIと誤認させて、ユーザーが本来ブラウザにだけ入力する情報(他サイトのユーザー名・パスワードなど)を盗む懸念があります。ですがFedCM UIはIDPのユーザーアカウント情報等サイトが取得できないメタデータを使うため、悪意サイトはアカウント情報を知ることができません(既にユーザーが侵害されていない限り)。推測はできるかもしれませんが、ブラウザは模倣困難なUIや関係するドメイン表示を推奨します。iframe等だけでFedCM UIを模倣し情報収集する攻撃は明らかに本物UIと異なります。さらにFedCM UIはトップレベルフレーム(または明示許可されたiframe)からのみ表示可能なので、特権UIはトップレベルフレームの意思でのみ表示され、悪意iframeが重要なページ内容を勝手に隠すことはできません。
7. プライバシー
本セクションはウェブにおけるフェデレーションIDのプライバシーリスク全体像を説明し、ブラウザ仲介設計のプライバシーリスクとメリット測定のための基礎とするものです。
7.1. 主体
このセクションではAPI呼び出しに関与する4つの主体とその振る舞いの期待を説明します。
-
ユーザーエージェントは§ 2 ブラウザAPIを実装し、RPとIDPコンテンツの実行コンテキストを管理します。ユーザーエージェントはユーザーから信頼され、RP・IDPからも間接的に信頼されている前提です。
-
RPはFedCM APIを呼び出してユーザー認証や情報取得を行うウェブサイトです。全てのサイトがAPIを呼び出せるため、RPがユーザー情報収集や利用を適切に制限するとは限りません。
-
IDPはFedCM呼び出しの対象となる第三者ウェブサイトで、トークン取得のために呼び出されます。通常IDPはRPより信頼度が高いですが、IDPがユーザー情報を不適切に利用する可能性もあります。またAPIで指定されたIDPがユーザーの知るIDPでない場合は、事前にユーザー情報を持たない可能性が高いです。
-
トラッカーはIDPでない第三者ウェブサイトで、FedCM APIを乱用してユーザーのウェブ横断追跡を試みる場合があります。トラッカーはRPによって意図的/非意図的に埋め込まれることがあり(例えば動的に読み込まれるスクリプトタグ等)、通常ウェブサイトのUIを変更せず検出困難です。複数サイトでトラッキングスクリプト追加に成功した場合、ユーザー情報を販売等に利用される可能性があります。FedCM APIがトラッカーによるウェブ横断追跡に使われてはなりません。
以上に基づき、プライバシー議論は以下の前提を置きます:
-
RP・IDP・トラッカーが、ユーザーの許可なしに特定ユーザーが特定サイトを訪れたことを知るのは許容されません。つまりユーザーエージェントは、特定ユーザーIDが特定サイトを訪問した知識をRP・IDP・トラッカーから隠す必要があります。ユーザーが許可すればRP・IDPへこの知識を共有できます。特にRPはユーザーIDを知ってはならず、IDPはユーザーがサイトを訪問したことをFedCMフローで許可取得前には知ってはなりません。
-
ユーザーエージェントは、ユーザーがIDPとRPが通信してユーザー識別を行う許可をいつ与えたか判断する責任があります。
-
一度ユーザーエージェントがユーザーの許可取得を認めた場合、RPとIDPは必要なユーザーアカウント情報を知ってもよいですが、RPは他のユーザーアカウント情報を知ってはなりません。
7.2. ネットワークリクエスト
本仕様は、FedCMによるfetchがRP指定のプロバイダーと同一オリジンになることを保証します。fetchでCookieを使う場合、指定オリジンのCookieが使われるため、任意オリジンを許すとCookie共有の混乱やプライバシー問題が生じます。fetchを同一オリジン化するにはリダイレクト無効化・URLのオリジン確認が有効です。
-
設定ファイルfetchはCookie・
client_id・リファラーなしで実行されるため、ユーザー追跡に使えません。誰でもfetch可能で、内容は公開情報扱いです。 -
アカウントエンドポイントfetchはIDPのCookie付きですが、
client_idやリファラーなしで追跡不可です。これはRPが新たに得る力ですが、過剰fetch防止は重要です。IDPはDoS対策済みが前提で、ユーザーエージェントはページごとFedCMフローを1つに制限し、追加呼び出しは即拒否します。FedCMフローはユーザー操作やタイマーで終わるためfetch数は問題になりません。IDPはこのfetchで多くを知りますが、詳細は後述。 -
クライアントメタデータエンドポイントfetchはIDPのCookieなしで、
client_idとリファラー付きです。これによりIDPは必要に応じてプライバシーポリシー・利用規約をユーザーエージェントに通知できます。タイミング攻撃を除けばRPはfetchで何も得ず、RP自体がCookieなしでfetchできるため問題ありません。 -
設計上、トークンfetchはサイト上のユーザーをIDPに公開します。Cookie・
client_id・リファラー付きで、ユーザーエージェントUIでユーザー操作が必要です。IDPはRPへ必要な情報を渡しフェデレーションサインイン/サインアップが可能となります。RP・IDPがユーザー許可なしにトークンfetchを強制することはできません(ユーザーエージェントは偽装不可)。 -
切断エンドポイントは、ユーザーがRPでFedCMフローを成功させた後のみfetch可能です。IDPへのcredentialedリクエストとなるため、FedCM利用後も無制限リクエスト不可です。切断時は必ず接続済みアカウントセットから1つ以上削除されるため、RPがIDPへCookie付きリクエストを無限に送り続ける仕組みにはなりません。
7.3. 攻撃シナリオ
このセクションでは、さまざまな主体がユーザー情報の取得を試みるシナリオについて説明します。考慮する可能性は:
本セクションにおいて、ある主体が情報収集に参加していると見なすのは、直接または間接的に上記の脅威実現を目的とする行動をとった場合です。
注: 間接的な共謀の例として、RPがIDP提供のスクリプトをインポートし、そのIDPがユーザー追跡を意図するケースが挙げられます。
議論の便宜上、本書ではサードパーティCookieがデフォルトで無効であり、トラッキング手段として機能しなくなっていることを前提とします。またリンクデコレーションやpostMessageによる「バウンストラッキング」への緩和策も何らか実装されているとします。これらのシナリオの多くは、これらが使えない場合にユーザー追跡がどう行われるかを検討します。詳細はPervasive Monitoring Is an Attackも参照。
7.3.1. マニフェストによるフィンガープリンティング
もしFedCM APIが2段階のマニフェスト(IdentityCredential作成アルゴリズム参照)を持たず、直接単一のマニフェストだけだった場合、以下のフィンガープリンティング攻撃が可能になります:
// 以下のコードはmanifest JSONファイルをfetchし、RPのオリジンを知ることができてしまう :( const cred= await navigator. credentials. get({ identity: { providers: [{ configURL: \`https://idp.example/ ${ window. location. href} \` }] } });
注: この攻撃の詳細はこちらで読めます。
ここでRPは、マニフェストをIDPから取得する際に自身を識別しています。これとFedCM APIが行う認証付きfetchが組み合わさることで、IDPはユーザーがどのウェブサイトを訪問しているか簡単に追跡できるようになり、ユーザーの許可も不要となります。これへの対策は§ 3.1 well-knownファイルの導入です。IDPドメインのルートにファイルがあることを強制することで、ファイル名からRP情報のフィンガープリントが生じないようにしています。
この場所に全マニフェストを置くこともできますが、実際にはそこから本マニフェストへの参照だけを置きます。これにより、IDPが将来的に複数マニフェストを必要とする場合にも柔軟に対応でき、単一ファイルだけに縛られません。またIDPの実装上、マニフェストの変更がドメインルート以外の任意ファイルに対して行えるため、更新の容易さにも寄与します。
7.3.2. タイミング攻撃
タイミング攻撃では、RPとIDPが共謀し、IDPが(RPのオリジン, IDPのユーザーID)のペアをユーザーの許可なく算出できるようにします。この攻撃は決定的ではなく、統計誤差の余地があります。なぜなら追跡には2つの断片的情報を突き合わせる必要があるためですが、それでもこの攻撃を困難にすることが重要です。ここではネットワークリクエストに大きなフィンガープリンティング要素(例:IPアドレス)がない場合を仮定します。これらはユーザーエージェントごとに異なり完全排除は困難ですが、ユーザーエージェントは今後これらへの対策が期待されます。ネットワークリクエストに結びつく情報はタイミング攻撃を容易にするため、特に対策の重要性が増します。
注: この攻撃の詳細はこちらで議論されています。
攻撃の流れ:
-
RPはAPI呼び出し時刻(A)を記録し、IDPに送信して、IDP側でRPのクライアントメタデータfetch到着時刻を記録します(Aはサイトと紐付く)。
-
認証付きリクエストがIDPに送信されるが、RPは明示的に識別されない。ただし上記リクエストに近い時刻に送信されるため、IDPは到着時刻(B)を記録(BはユーザーIDと紐付く)。
-
IDPはAとBを突き合わせて(サイト, ユーザーID)ペアを高確率で割り出す。フィンガープリンティングがあれば精度はさらに上がる。
この種の相関はFedCM無しでもクロスオリジントップレベルナビゲーション等で可能ですが、FedCMでタイミング分解能が上がったりユーザーへの可視性が下がった場合(例:IDPが空アカウントを返してブラウザUI非表示にする等)、問題は悪化します。
ユーザーエージェントは、ユーザー保護のため、この攻撃への対策を相互運用可能な形で講じるべきです。
7.3.3. IDPによる侵入
Target Privacy Threat Model § hl-intrusionより
プライバシー被害はサイトが何かを知ることからだけ起きるとは限らない。
侵入とは、個人の生活や活動を妨害・中断する侵襲的行為である。個人が放っておかれたい願望を妨げたり、時間や注意力を奪ったり、活動を中断したりする。
フェデレーションの文脈での侵入は、RPとIDPが共謀し、ユーザーの意図に比して過剰にログインを勧める場合に発生します。望ましくない通知同様、RPがIDPと共謀し、ユーザーのログインを執拗に促すケースです。
ユーザーエージェントはユーザー操作を仲介し、ユーザー意図やプライバシーリスクに応じて適切なUIを提供することで、このような侵入を緩和できます。例えば、ユーザー意図の確信度が高い場合は目立つ/強いモーダルダイアログを表示し、確信度が低い場合は控えめなUIヒントを表示するなどです。
ユーザーエージェントは、リスクに応じてユーザー体験の妨害度合いを調整することも可能です。例えば、指示付き識別子を交換する場合は意図しない結果に自信が持てるため、より強い体験を提供し、グローバル識別子交換の場合はより控えめな体験にするなどです。
7.3.4. クロスサイト相関
この攻撃は、複数のRPが共謀し、ユーザーデータを使ってユーザーを相関付け、より詳細なプロフィールを構築する場合に発生します。ユーザーが氏名、メールアドレス、電話番号などを複数のリライングパーティに自発的に提供した場合、それらのRPは協力して、そのユーザーやユーザーの複数サイトでの活動のプロフィールを作成できます。これは複数RPのアカウントデータベース間でユーザー情報を「結合」することに相当し、「ジョイン」と呼ばれる場合もあります。このような相関やプロフィール構築はユーザーの管理外であり、ユーザーエージェントやIDPの監視範囲外です。
-
ユーザーはIDPを使ってRP1(宝石を販売する)にサインインし、RP1にメールアドレス user@email.example を提供する。
-
ユーザーはIDPを使ってRP2(住宅を販売する)にサインインし、RP2にメールアドレス user@email.example を提供する。
-
ユーザーはRP1で結婚指輪のコレクションを閲覧する。
-
RP1はユーザーが結婚指輪を探していることを、帯域外でRP2に伝える(メールアドレス user@email.example を共有)。
-
ユーザーはRP2で住宅の在庫を閲覧する。
-
RP2は、ユーザーがRP1で結婚指輪を探している事実を利用して、広告や住宅の在庫検索を調整する。
-
ユーザーは、RP2が自分が結婚指輪を探していることを知っていることに驚く。
RP間でユーザーデータをバックチャネルで結合する問題は、識別可能なユーザーデータが広がることに起因しています。これを解決するためには、特定のIDPごとにユーザー固有で、他のRPと相関できない有効な識別子(directed identifier)を発行する方法があります。過去には、ユーザー名やIDP、RPなどを一方向ハッシュして実現するスキームも存在しました。こうした識別子は一意であり、他のRPと相関させることはできません。
7.3.5. 無許可のデータ利用
もう一つの攻撃は、RPやIDPがユーザーの情報をユーザーが許可していない目的で利用する場合です。ユーザーがIDPによるRPへの情報提供を許可した場合、その許可はサインインやパーソナライズなど特定の目的に限定されています。例えば、RPがそのデータをユーザーが予期しない、かつ許可していない目的(スパムリストへのメールアドレス販売など)に利用する可能性があります。スパムリスクはdirected identifierを使っていても存在します。
7.3.6. RPによるフィンガープリンティング
この攻撃は、RPがクライアント状態ベースのトラッキングを使ってユーザーを識別する場合に発生します。ウェブにクライアント状態を何らか公開するAPIは、フィンガープリンティングのベクターになるリスクがあります。このAPIの目的は、ユーザーがRPに自身を識別させることです。そして、ユーザーはその識別へのアクセスを取り消す(例:ログアウトする)ことができなければなりません。しかし、トラッキング目的のRPは、過去にログインしたユーザーを検出するために状態を保持し続けることがあります:
7.3.7. 二次利用
二次利用とは、個人から収集した情報を、本人の許可なく収集時と異なる目的で利用することです。この攻撃は、IDPがサインイン用に収集した情報を他の目的で悪用する場合に発生します。
既存のフェデレーションプロトコルでは、IDPがどのサービスがトークンを要求しているかを知る必要があります。IDプロバイダーはこの事実を利用し、同じアカウントでフェデレーションを利用したユーザーのサイト横断プロフィールを構築できます。例えば、このプロフィールはIDPが管理するサイトでユーザーが閲覧している際にターゲット広告を表示する目的で使われる可能性があります。
このリスクは、IDPが事前にユーザーアカウント情報を持たない場合(例えば正規のIDPでない場合)でも存在し得ます。なぜならFedCMリクエストがIDPにcredentialedで送信されるからです。特に、RPがIDPと共謀し、§ 7.3.2 タイミング攻撃による追跡を可能にしている場合は、その可能性が高まります。
IDPによるユーザー追跡の防止は難しい:RPはセキュリティ(トークン再利用・不正防止)のため、IDトークンに記載される必要がある。IDPにRPを秘匿しつつ、トークン再利用防止を実現する暗号技術も開発されている(Mozillaのpersonasなど)。しかし、これらの手法は本仕様には採用されていない。
8. 拡張性
注: 拡張メカニズムについて説明します。
9. 謝辞
注: 謝辞セクションを記載します。
10. FPWD課題
注: WGは以下の課題をクリティカルなオープン課題としてラベル付けしており、Candidate Recommendation公開前に正式に対応する必要があります。- Issue 240: ユーザーがRP列挙外のIdPを利用できない
- Issue 317: アカウントリストのメールに関する懸念
- Issue 319: 複数IDPの利用許可
- Issue 320: Sec-FedCM-CSRFとSec-Fetch-Modeの違い
- Issue 352: パフォーマンス測定のIDPへの共有
- Issue 407: [Context API] - Authz / スコープ指定能力との関係
- Issue 428: Identity AssertionsエンドポイントでのCORS強制
- Issue 441: FedCM対応のためにIDPが追加インフラを必要とする
- Issue 442: 未ログインIDPがこのフローで成功する道がない
- Issue 467: FedCM許可後のStorage Access APIによるクロスサイトCookieアクセスのユースケース?
- Issue 488: サインイン意図表示後にサインイン失敗でユーザーが混乱する可能性
- Issue 511: 追加アカウントへのサインイン許可
- Issue 517: ユーザーエージェントが"Connected Accounts Set"を柔軟に使えるようにする
- Issue 537: 同一サイトサブリソースからIDPログイン状態を設定可能に
- Issue 552: IDPがeTLD+1内で複数設定ファイルを利用可能に
- Issue 553: IDPが文脈ごとに異なるアカウントリストを公開可能に
- Issue 555: IdPがポップアップウィンドウでリクエストを継続・完了可能に
- Issue 556: ID assertion endpointへの任意パラメータ渡し
- Issue 559: RPがユーザープロフィール属性を選択的に要求可能に
- Issue 578: IdPがRPにStringではなくJSONオブジェクトを返せるように
- Issue 585: IdP登録とRPのマッチに"type"指定を許可
- Issue 587: なぜSameSite=noneが必須なのか?
- Issue 599: FedCMのOAuthプロファイル
- Issue 609: SpecでSameSite=Strict cookie送信と記載
- Issue 616:
params仕様統合後nonceパラメータ廃止 - Issue 618: ナビゲーショナルトラッキング緩和の分類/リスト削減前に認証フローの連鎖対応
- Issue 620: 登録IdPのeTLD+1で容易にデプロイ可能に
- Issue 625: getUserInfoでは返却アカウントが先頭に
- Issue 626: PP/TOS要件が自動再認証とは異なる
- Issue 627: webdriverコマンドでPP/TOSを開く機能追加