FedCM(Federated Credential Management)を試してみた

# はじめに
ID連携(OpenID ConectやSAML等)は、3rd Party Cookieのメカニズムに依存している部分がある。一方、プライバシー保護の観点から、3rd Party Cookie廃止の流れがある。この3rd Party Coookieが廃止となっても、ID連携をサポートするために必要な機能を提供する仕組みとしてFedCMというプロトコルがGoogleによって開発されている。このFedCMの機能について、様々なBlogやWebinarで見聞きしてはいたが、実際に試してみて気になった点を備忘録として記載した内容です。

# FedCM(Federated Credential Management)とは
FedCMは、以前はWebIDと呼ばれており、[W3C](https://www.w3.org/TR/fedcm/
)にて仕様が議論されている。
FedCMは、Chrome,Edge等のブラウザで機能(ブラウザ対応状況は[こちらを参照](https://developer.mozilla.org/en-US/docs/Web/API/FedCM_API#browser_compatibility))し、3rd Party Cookieやリダイレクトを必要とせず、IdPにログイン済みの状態であることを利用し、プライバシーを保護しながらRP（サービス提供サイト）上でIDフェデレーションサービスを利用できるようにするのためのメカニズムです。
FedCMは、XやStackoverflow等、様々なサイトに実装されており、サイトにアクセスした際、右上に下記のようなGoogleアカウントを利用してログインするかを求める動作をします。ここで続行ボタンをクリックすると、Googleサイトに遷移することなくログインが完了し、引き続きサイトを利用する事ができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/247555/80fd7f3a-dc1d-b90a-b8d5-3c0cb798ebb8.png)

大きくは、RPから提供されるJavaScriptにより呼び出され、ブラウザ(User Agent)からIdPに対していくつかのリクエストが呼び出し、IDフェデレーションを実現します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/247555/4606e1d4-8af4-7e85-8f90-ab00ca8c4303.png)


# FedCMの実装
FedCMによるログインフローは、下記のようになります。
![fedcm.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/247555/75bf0021-233f-eb91-ada8-4bfb58f7074e.png)

上図のように、最初と最後にRP側で処理が行われます、その間、IdP側に画面遷移は行われず、Step.11でRP側の画面上でログインをワンタップするだけでRPへのログインが完了します。

それでは、各ステップ毎に確認していきたいと思います。
## Step.0 事前にIdPにログイン
事前準備として、ユーザーは、IdPにログインしておきます。認証方法は、IdPの実装に依存します。

## Step.1
ユーザーは、サービスを受けるためにRPにアクセスします。

## Step.2
Step.1のレスポンスとして、FedCMを呼び出すためのJavaScriptをRPが応答します。
ここには、OpenID Connectでクライアント登録を行うように、FedCMでもIdP側にRPの情報を登録する必要があり、事前にIdPから情報を入手しておく必要があります。
RPは、入手したIdPやクライアント情報を、navigator.credentials.get()を使用してIdPを呼び出します。
IdPを呼び出すためには、configURL,clientIdが必須となっており、その他、contextプロパティを使用して、signin(default)やsignup,use,continue等の事前に定義された認証コンテキストに対応できたりします。

RPの実装としては、このStepで行われるJavaScript応答の内容と、Step.15のtoken処理の方法がメインの実装となります。

## Step.3
Step.2で得られたConfigURLの情報から、IdPにアクセスします。自環境では、DNSに登録せずローカル環境で試しており、hostsファイルにIdPのFQDNしか登録していなかった。そのためFedCMが起動せず、どの構成に問題があるのかに気が付くまでに時間を要した。原因は、FedCMの仕様にも記載されているのだが、configURLに定義されているeTLD+1 URLにアクセスされているため、eTLD+1の名前解決が必要な点にありました。また、調査する際、ブラウザの開発者モードでアクセス状況の確認を試みたのだが、FedCM API内部で呼ばれているためか、IdPへのアクセスは記録されず、原因の特定には時間を要した。
また、IdPには認証済みだが、このアクセスは、非認証の状態(セッションCookie無)としてアクセスされる。

参考（GoogleのIdPの場合）：ログインサイトがhttps://<foo>accounts<foo>.google.comのため、https://<foo>google.com<foo>/.well-known/web-identityへのアクセスとなる。実際は、https://<foo>www<foo>.google.com/.well-known/web-identityにリダイレクトされている。

<details><summary>Google IdPの.well-known/web-identity例</summary>

```
#curl  -I -H "Content-Type: application/json" -Ss -k "https://google.com/.well-known
/web-identity"
HTTP/2 301
location: https://www.google.com/.well-known/web-identity
<省略>

#curl  -L -H "Content-Type: application/json" -Ss -k "https://google.com/.well-known
/web-identity"
{
  "provider_urls": [
    "https://accounts.google.com/gsi/fedcm.json"
  ],
  "accounts_endpoint": "https://accounts.google.com/gsi/fedcm/listaccounts",
  "login_url": "https://accounts.google.com/gsi/fedcm/signin"
}
```
</details>

## Step.4
.well-known/web-identityへの応答には、最低限provider_urlsの情報が含まれていれば良く、その他には、複数構成のためにaccounts_endpointやlogin_url情報を含めることができる。

## Step.5
次にブラウザは、IdPのconfig endpointへアクセスを行う。このアクセスもまた、非認証の状態(セッションCookie無)としてアクセスされます。

## Step.6
IdPは、accounts_endpoint、id_assertion_endpoint、login_urlを応答する必要があり、その他、オプショナルとして、client_metadata_endpoint情報、disconnect(接続解除)情報、name情報(IdPの名称等)、branding情報（ログインボタンの色、背景色、アイコン、サイズ等）を応答する事ができます。

## Step.7
次にブラウザは、IdPのaccount endpointへアクセスを行う。ここで初めて、認証状態(セッションCookie有)としてアクセスされます。

## Step.8
IdPは、アカウントリストを応答します。id,name,emailを必須項目とし、given_name,picture等をオプショナルとして応答します。ここで、ユーザーがログインしていない場合は、HTTP 401で応答します。

## Step.9
次にブラウザは、IdPのmetadata_endpointにclient_idと共にアクセスします。このアクセスは、非認証の状態(セッションCookie無)としてアクセスされます。

## Step.10
IdPは、client metadataを応答します。これには、privacy_policy_url,terms_of_service_urlの情報が含まれており、ログインボタン内の"プライバシーポリシー"や"利用規約"のリンク先となります。

## Step.11
次にユーザーはブラウザ上でログインを行うのか(複数アカウントがある場合は、どのアカウントでログインするか)を選択します。

## Step.12
次にブラウザは、IdPのid_assertion_endpointにStep.11で選択したaccount_id情報と共にアクセスします。
このアクセスは、認証状態(セッションCookie有)としてアクセスされます。
このアクセスの際、client_id,nonceの情報、disclosure_text_shownとして、IdPがRPと共有しようとしている特定の情報をユーザーに明示的に示しているかの情報を連携します。

## Step.13
Step.12で選択されたaccount_idに対するtokenを生成し、ブラウザに応答します。この際、tokenの形式と構造はIdPに依存しており、FedCMとは関係が無く、RPはIdPの実装に従う必要があります。

## Step.14
IdPから受け取ったtokenをブラウザ経由でRPに連携する訳ですが、フローが完了するとget() Promiseは、IdentityCredentialオブジェクトで解決され、そのtokenをどのようにして連携するかは、RP側で決めて実装します。

## Step.15
RP側でブラウザから送信されたtokenを元に認証処理を行います。これは、RP独自の実装となりますが、tokenはjson形式で連携されるため、JWT認証機能が提供されているWebアプリケーションを選択することによって、実装が容易になるものと思います。昨今、多くのWebアプリケーションには、JWT認証機能が提供されているものと思います。

## Step.16
RP側での認証結果が得られます。

# FedCMを使ってみて
IdPにログインしている事を利用し、ワンタップでログインできるため、ブラウザのプロファイルと連携し、ChormeであればGoogleアカウント、EdgeであればMSアカウントでログインするにはすごく便利な機能だと感じた。一方、余りプライバシーに関心のない方であれば、ワンタップで容易にサインアップが出来てしまうため、あらゆるサイトにそれほど意識せず、IDを作成してしまうのでは？と気になった。
その他、学習してみて、[CHIPS(Cookie Having Independent Partitioned State)](https://developers.google.com/privacy-sandbox/cookies/chips?hl=ja)と呼ばれる、ブラウザでのCookieの管理の仕方が拡張されている点や、[Storage Access API](https://developers.google.com/privacy-sandbox/cookies/storage-access-api?hl=ja)と呼ばれるAPIの存在も知れてよかった。

# 補足　3PCD(3rd Party Cookie Deprecated)の現状
Googleは、これまで何度か3PCDを延長してきたが、[2024/7/22の発表](https://privacysandbox.com/news/privacy-sandbox-update/)で廃止を行わない方針を決定している。
> In light of this, we are proposing an updated approach that elevates user choice. Instead of deprecating third-party cookies, we would introduce a new experience in Chrome that lets people make an informed choice that applies across their web browsing, and they’d be able to adjust that choice at any time. We're discussing this new path with regulators, and will engage with the industry as we roll this out.
※過去の延長の経緯などは、[こちらのサイト](https://digitalidentity.co.jp/blog/marketing/chrome-cookie-remove.html)が参考となります。
一方、Googleは3PCDを撤回していますが、Safari(Apple)やFirefoxはすでにを廃止しており、[Edgeも廃止方向](https://blogs.windows.com/msedgedev/2024/03/05/new-privacy-preserving-ads-api/)で進んでいます。[statcounterのサイト](https://gs.statcounter.com/)によると、Chromeのブラウザシェアが約65%とは言え、他ブラウザが廃止としている中、いずれChromeも廃止することになると推測します。

# 参考
W3C: https://www.w3.org/TR/fedcm/
mdn web docs: https://developer.mozilla.org/en-US/docs/Web/API/FedCM_API
Goolge FedCM API: https://developers.google.com/privacy-sandbox/cookies/fedcm?hl=ja
Goolge FedCMに移行する: https://developers.google.com/identity/gsi/web/guides/fedcm-migration?hl=ja
You Tube: https://www.youtube.com/watch?v=pou52euG7Qk