第9回 GA4 Data APIをCloudflareビルドで使う―サービスアカウントが使えずOAuthへ切り替える
GA4 Data APIで取得した記事別PVをCloudflare Pagesのビルドでも使うため、サービスアカウント、組織ポリシー、OAuth本番化、ADC再認証、Cloudflare Secret登録までを確認した。

第8回では、GA4 Data APIから記事別PVを取得できるところまで進めた。
ローカルでは node scripts/ga-pageviews.mjs を実行すると、pagePath と screenPageViews を取得できる。
次は、このデータをゆまラボのTOPページへ反映したい。ただし、ゆまラボはCloudflare PagesのビルドでAstroを生成している。ローカルのgcloud認証だけでは、Cloudflareのビルド環境からGA4 Data APIへ接続できない。
Cloudflare側でもGA4を読める認証方法を作る。
最初はサービスアカウントを使う予定で進めたが、途中でGoogle Cloudの組織ポリシーに止められた。そのため、既存のOAuth認証をCloudflareビルドでも使える形へ変更した。
サービスアカウントから試す#
Cloudflareのビルドでは人がブラウザでログインできない。そこで最初に考えたのが、GA4読み取り専用のサービスアカウントを作り、JSONキーをCloudflareのSecretへ登録する方法だ。
Google Cloudで yumalabo-ga4-build というサービスアカウントを作成し、JSON形式の秘密鍵を作ろうとした。
ところが、キーの作成画面から先へ進めなかった。

表示された制約は次のものだ。
iam.disableServiceAccountKeyCreation
画面には「サービス アカウント キーの作成が無効になっています」と表示され、組織ポリシーによってキー作成がブロックされていた。ここで最初の予定が崩れた。
Google Cloudの公式ドキュメントでも、この制約が適用されているプロジェクトではサービスアカウントキーを作成できないと説明されている。
ここでサービスアカウント方式をそのまま続けることはできなくなった。
新しい制約は未適用。ただし以前の制約が有効#
組織ポリシーを確認すると、新しいマネージド制約 iam.managed.disableServiceAccountKeyCreation 自体は未適用になっている。
ただし、画面上部には以前の制約 iam.disableServiceAccountKeyCreation が有効と表示されていた。
「以前の制約を表示」から確認すると、こちらは親ポリシーを継承し、現在のプロジェクトで「適用済み」になっていた。

つまり、キーを止めていたのは新しい制約ではなく、以前からある組織ポリシーだ。
組織ポリシーの変更権限もない#
次に、現在のプロジェクトだけポリシーを変更できるか確認した。
しかし「ポリシーを管理」は使用できず、必要な権限がないと表示された。

表示された不足権限には、orgpolicy.policies.create、orgpolicy.policies.delete、orgpolicy.policies.update、orgpolicy.policy.set が含まれていた。
Google Cloudも、iam.disableServiceAccountKeyCreation が有効な場合はキーを使わない認証方式を先に検討するよう案内している。
ここで組織ポリシーを解除する方向には進めず、サービスアカウントのJSONキー方式を中止した。
既存のOAuth認証をCloudflareでも使うことにする#
第8回では、ローカルのgcloud Application Default Credentials(ADC)を使ってGA4 Data APIへ接続している。
そこで、サービスアカウントを新しく使うのではなく、このOAuth認証をCloudflareのビルドでも利用する方向へ切り替えた。
ただし、そのまま認証情報を持ち込めば済む話でもない。
Google Auth Platformの「対象」を確認すると、公開ステータスは「テスト中」、ユーザーの種類は「外部」になっている。

Googleの仕様では、ExternalのOAuthアプリがTestingの状態で通常のOAuthスコープを要求する場合、テストユーザーの認可は7日で期限切れになる。refresh tokenも同様に期限切れになる。
Cloudflareの自動ビルドで使う認証が7日で切れる状態では運用できない。そのため、OAuthアプリ側の設定も変更することにした。
ブランディングとanalytics.readonlyを設定#
Google Auth Platformのブランディングには、ゆまラボの情報を登録した。
- ホームページ:
https://bringain.com/ - プライバシーポリシー:
https://bringain.com/privacy/ - 承認済みドメイン:
bringain.com - 利用規約:今回は未設定
- ロゴ:今回は未設定
次に「データアクセス」で、GA4の読み取りに必要なスコープを追加した。
https://www.googleapis.com/auth/analytics.readonly

記事別PVを読むだけなので、書き込み権限は追加していない。
その後、「アプリを公開」から公開ステータスを本番環境へ変更した。

画面上にはアプリの検証が必要という案内が残った。ただ、自分で使う個人用途で利用者を広げる予定はないため、検証申請は行わずに進めた。Googleのヘルプでは、100ユーザー未満のPersonal Useアプリは検証完了が必須ではないとされている。
ADCを一度取り消して本番状態で認証し直す#
OAuthアプリを本番環境へ変更したため、第8回で作ったADCを一度削除して認証を取り直した。
まず既存のADCを取り消す。
gcloud auth application-default revoke
次に、OAuth Desktop ClientのJSONを指定し、GA4読み取り用スコープを含めてログインする。
最初は analytics.readonly だけを指定したところ、gcloudから次のエラーが返った。
Invalid value for [--scopes]:
https://www.googleapis.com/auth/cloud-platform scope is required but not requested.
--scopes を明示する場合、gcloud側で必要になる cloud-platform も含める必要があった。
最終的に使った形は下記。
gcloud auth application-default login `
--client-id-file="C:\path\to\client_secret.json" `
--scopes="https://www.googleapis.com/auth/cloud-platform,https://www.googleapis.com/auth/analytics.readonly"
Google CloudのADCドキュメントでも、Google Cloud外のサービス向けスコープを追加する場合は、OAuth Client IDを --client-id-file で渡し、--scopes を指定する方法が案内されている。
認証フローを完了すると、gcloud側でも認証完了画面が表示された。

gcloud auth application-default print-access-token でもアクセストークンを取得できた。ただし、トークン自体は認証情報なのでスクリーンショットには使用しない。
GA4 Data APIをもう一度実行#
認証し直した状態で、第8回のスクリプトを再実行した。
node scripts/ga-pageviews.mjs
結果は正常。

この時点では83件取得でき、/blog/、各記事の pagePath、screenPageViews が出力された。
認証方式を作り直した後も、第8回で作ったGA4 Data API取得処理はそのまま利用できた。
ADCのJSONをCloudflare Secretへ登録#
最後に、WindowsのADCファイルをCloudflare側へ渡す。
ADCはWindowsでは次の場所へ保存される。
%APPDATA%\gcloud\application_default_credentials.json
このJSONには client_id、client_secret、refresh_token などが含まれるため、Gitには入れない。
Cloudflare Pagesの「Variables and Secrets」で、次のSecretとして登録した。
GA4_ADC_JSON

値は暗号化され、画面上から内容を確認できない状態になっている。
Cloudflare Pagesでは、ビルド時に環境変数やSecretを利用できる。
Cloudflareで使う認証までの流れ#
第8回では、ローカルでGA4 Data APIを呼び出せるところまで進めている。
Cloudflareビルドへ認証情報を渡す準備を進める途中で、認証方式を変更することになった。
最終的な流れは次のようになった。
サービスアカウントを作成
↓
JSONキー作成を試す
↓
iam.disableServiceAccountKeyCreation でブロック
↓
親ポリシーからの継承を確認
↓
ポリシー変更権限もないことを確認
↓
既存OAuth方式へ切り替え
↓
OAuthアプリをTestingからProductionへ変更
↓
analytics.readonlyを追加
↓
ADCを再認証
↓
GA4 Data APIで取得成功
↓
GA4_ADC_JSONをCloudflare Secretへ登録
サービスアカウントのキー禁止を解除せず、既存のOAuth認証を再利用する形にした。
次は、この GA4_ADC_JSON と第8回のGA4取得処理をAstroのビルドへ接続し、TOPページへ人気記事3件を表示する。


