🔑

Cloud Functions for Firebase の Firestore トリガーで変更者を知る方法

2024/11/02に公開

概要

Cloud Functions for Firebase(長いので、以下 Functions とします)では、onDocumentCreatedのようなトリガーを使って Firestore ドキュメントの変更をフックできます。これらの第二世代トリガーでは、「誰が変更を引き起こしたか」の情報を取得することはできませんでした。

firebase-functions@4.9.0にて、下記のトリガーが追加されたことで、認証情報を取得することができるようになりましたので簡単に使い方などを記載したいと思います。

  • onDocumentCreatedWithAuthContext
  • onDocumentWrittenWithAuthContext
  • onDocumentDeletedWithAuthContext
  • onDocumentUpdatedWithAuthContext

https://github.com/firebase/firebase-functions

参考資料

この記事の執筆現在、Functions の日本語公式ドキュメントにはまだこれらのトリガーが反映されていません。
[12/18 追記] 現在の日本語公式ドキュメントには反映されていました 👏
日本語公式ドキュメント

原版(英語)の公式ドキュメントには、同箇所が下記のように記載されています。
英語公式ドキュメント

実装

基本的な使い方は従来のトリガーと同様ですが、引数で渡されるeventオブジェクト内に、AuthContextにあたる情報が拡充されます。

import { onDocumentWrittenWithAuthContext } from "firebase-functions/v2/firestore"

export const onUserWritten = onDocumentWrittenWithAuthContext("users/{userId}", (event) => {
  const { authType, authId, authClaims } = event;
  ...
}

拡充される情報の仕様はspecに定義がある通り、以下のようになります。

field constraint content
authType 必須 app_user, user, service_account, api_key, system, unauthenticated, unknownのいずれか
authId 任意 authTypeによって異なり、uidやメールアドレスなど状況に合わせた内容
authClaims 任意 プリンシパルを表す claims JSON文字列

各フィールドの詳細はspec原文を参照ください。

ユースケース

誰がどのような方法で変更を行ったかが検出できるため、変更ログを Functions で自動生成したり、公式ドキュメントのサンプルにあるように、変更者情報をドキュメントに追記したりする利用法が考えられます。

import { onDocumentWrittenWithAuthContext } from "firebase-functions/v2/firestore"

export const onUserWritten = onDocumentWrittenWithAuthContext("users/{userId}", (event) => {
  return data.after.ref.set({
    created_by: event?.authId,
  }, { merge: true }); 
}

このとき実際には、authIdに入る情報がauthTypeによってまちまちである点に注意が必要です。例えば、Firebase Authentication により認証済みのユーザが Firestore のクライアントSDK経由で情報を書き込むような状況では、authTypeapi_keyとなり、authIdには Authentication の uid が格納されています。開発者(管理者権限)が直接 Firebase のUIから変更を行った場合、authTypeunknownとなり、authIdはメールアドレスとなります。

各プロジェクトごとの想定される認証状態と操作で内容を確認したほうがよさそうです。

その他

リリース直後はこのトリガーを利用するとローカルのエミュレータがクラッシュするなどの問題がありました(今は修正済み)。現在も Google Cloud Identify Platform を利用して認証をマルチテナント化している場合に tenantId を知る方法がない(こちらのissue)など、まだいくつか問題も残っていそうですが、デフォルトテナントのみでの利用であれば今のところ問題なく動作していそうです。

まとめ

第二世代の記法でも Auth Context が利用できるようになり、できることの幅が広がりました。これらのトリガーについての情報が日本語ドキュメントにないこともあり、あまり展開されていないように思いましたので書いてみました。どなたかのお役に立てば嬉しいです。

Discussion