Admin Directory APIを使わずにGASでGoogle Groupsにメンバーを追加する

# はじめに
とある団体で、フォームに回答したアカウントを自動でGoogle Groupsにメンバーとして追加する、という機能を実現する必要がありました。

GASを用いてGoogle Groupsにメンバーを追加する方法としては、しばしば[Admin Directory API](https://developers.google.com/workspace/admin/directory/v1/guides?hl=ja)が紹介されます。

https://qiita.com/himanande/items/7e8374b0bb992cdcbb04

https://qiita.com/imura/items/07b05a2421ef9406b1f3

https://dev.classmethod.jp/articles/g-suite-groups-insert/

しかし、この方法の最大の欠点として、Google Workspaceの管理者でないと(恐らく)利用できない、というものがあります。実際、公式ガイドには

> Directory API は RESTful Admin SDK API の一部であり、Google Workspace アカウントが所有する管理者制御リソースをプログラムで作成、管理するために使用できます。

という記載があり、管理者でないユーザーで試してみても権限不足で利用できませんでした(もしかしたら何らかの方法を使えば利用できたかもしれませんが、後述するCloud Identity APIの方法にすぐ切り替えたため、詳しい検証はしていません)。

Google Groups関連で他に使えるものとしては、[GroupsApp](https://developers.google.com/apps-script/reference/groups/groups-app?hl=ja)もありますが、こちらは読み取り専用であり、メンバーの追加には使えません。

調査を続けていたところ、どうやら[Cloud Identity API](https://cloud.google.com/identity/docs?hl=ja)を用いて所望の動作を実現できそうだ、ということがわかりました。

https://qiita.com/nobrin/items/e5594150ee99a705c553

https://zenn.dev/ohsawa0515/articles/cloud-identity-gas

今回はこの利用方法や自分が躓いた点について、備忘録として記載していきます。

なお、この操作を行ったのは2-3ヶ月ほど前なので、途中で遭遇したエラーメッセージなど、一部あやふやな部分があります。ご了承ください。

# GCPの準備とGASとの連携
詳細は以下の記事などを参考にしてください。

https://zenn.dev/ameyo/articles/3dd7449b6d37ba

1. [Google Cloud コンソール](https://console.cloud.google.com)から新しいプロジェクトを作成
1. 作成したプロジェクトに切り替えた後、ナビゲーションメニュー→「Cloudの概要」→「ダッシュボード」を開き、プロジェクト番号を控えておく
1. ナビゲーションメニュー→「APIとサービス」→「OAuth同意画面」を開き、「ユーザーの種類」「アプリ名」「ユーザーサポートメール」「デベロッパーの連絡先情報」を入力
1. ナビゲーションメニュー→「APIとサービス」→「ライブラリ」から「Cloud Identity」を選択した後(要検索)、APIを有効化
1. GASのプロジェクトを開き、「プロジェクトの設定」(歯車アイコン)中の「Google Cloud Platform（GCP）プロジェクト」に先程控えておいたプロジェクト番号を貼り付けて、GASとGCPとの連携を行う

# GASの設定
GASとGCPの連携ができたので、GASからCloud Identity APIを利用できるようになります。
グループへのメンバーの追加・削除を行うコードは以下の記事(再掲)にすべてまとまっています。自分もほとんどこれを流用しました。

https://zenn.dev/ohsawa0515/articles/cloud-identity-gas

一点変えたのは、メンバーの追加を行う関数にロールの設定を行う引数`role`を追加した、というところです。
[groups.membership](https://cloud.google.com/identity/docs/reference/rest/v1/groups.memberships)にはロールに関するフィールド`roles`があるので、引数`role`に指定されたロールをここで設定しています。

注意点として、`MANAGER`または`OWNER`と設定したいメンバーも`MEMBER`ロールを所持している必要があります。
上記リファレンスには(多分)記載がないのですが、[Groups APIの概要](https://cloud.google.com/identity/docs/groups?hl=ja)には

> - `MEMBER`。特別な権限は付与されていません。すべてのメンバーシップには、少なくとも `MEMBER` のロールが必要です。

と記載されているので、必要になります。

```JavaScript
function insertMember(userEmail, groupEmail, role) {
  const url = `https://cloudidentity.googleapis.com/v1/${getGroupId(groupEmail)}/memberships`;
  const roleArray = role === "MEMBER" ? [
    {"name": "MEMBER"}
    ] : [
      {"name": "MEMBER"},
      {"name": role}
    ];
  let body = {
    "preferredMemberKey": { "id": userEmail },
    "roles": roleArray
  };
  let response = UrlFetchApp.fetch(url, {
    headers: {
      Authorization: `Bearer ${getToken()}`
    },
    method: "POST",
    contentType: "application/json",
    payload: JSON.stringify(body),
    muteHttpExceptions: true
  });
  console.log(response.getContentText());
  return response.getContentText();
}
```

# OAuthスコープの手動設定

このままコードを実行して無事成功、と行きたいのですが、Cloud Identity APIの権限がない、といったエラー(だったはず?)が出ました。

「承認が必要です」というダイアログが出て権限を許可する、というのがよくある流れだと思うのですが、コードを実行してもそのようなダイアログが自動で出てくることはありません。

どうやら、Cloud Identity API等のOAuthスコープを手動で設定する必要があるようです。
以下の記事を参考に`appscript.json`を加筆する必要があります。

https://zenn.dev/seya/articles/709659242512a7

参考元の記事には`appscript.json`に記載すべき内容が記載されていたので、他に必要な権限を加筆した上で再度コードを実行すると、無事「承認が必要です」というダイアログが表示され、権限を許可することで正常に動作することが確認できました。

# おわりに

日本語の記事ではGoogle GroupsのAIPに関する記事のうちCloud Identity APIに言及されているものが少なかったため、Admin Directory APIを使えない環境でもメンバーの追加をGASでできる、ということに辿り着くまでかなりの時間を要してしまいました。

限定的な状況かとは思いますが、個人の(Google Workspaceではない)アカウントを使う場合や、Google Workspaceの管理者権限を有さない場合は、この記事の手順通りにやれば上手くいくはずです。