K.Y. Design
K.Y. Design
K.Y. Design

【Zoom API】JWTが作成出来ない時の対処法


こんにちは、K.Y. Designの幸です。
今回はZoomとGAS(Google Apps Script)の連携が必要なツールを作成するにあたってつまずいた点がありましたので、その原因と対処法について書いていきたいと思います。

Developer privilege is required. Please contact your account admin.と表示され、Createボタンがグレーアウトに…

問題の画面は以下の通りです。

今回はZoomとGASの連携のためにZoom App MarketplaceでJWTを作成しようとしたのですが、どういうわけかDeveloper privilege is required. Please contact your account admin.と表示され、Createボタンがグレーアウトしてクリックができないという状況になっていました。

いったいこれは何が原因なのでしょうか?

結論:原因はJWT appを作成しようとしたZoomアカウントが他のアカウントの”メンバー”だったということ

実はZoomにはアカウントのロールという機能があります。
詳しくはこちらをご覧いただきたいのですが、zoomアカウントにはオーナー管理者メンバーの3つのロール(役割)を付与することができるようになっています。

使用用途の例としては、会社の代表アカウントをオーナーに割り当て、その配下に社員のアカウントをメンバーとして紐付けていき、アクセスコントロールを行なっていくという感じです。

実際にオーナー側とメンバー側のアカウントプロフィールを見にいくと、それぞれ以下のような表示になっているはずです。

オーナー側

メンバー側

このような状況だと、オーナーのアカウントからでしかJWTを作成できなくなってしまうので、メンバーアカウントからJWTを作成しようとするとDeveloper privilege is required. Please contact your account admin.(訳:開発者権限が必要です。アカウント管理者に連絡してください。)という表示が出てしまうのです。

では、この問題をどうやって解決すればよいのでしょうか?

3つの解決策

このような状況になってしまった場合、下記の3つのやり方で解決することができます。

  1. 新しい別のアカウントを作成し、そのアカウントでJWTを作成する。
  2. メンバーのアカウントをオーナーから切り離してからJWTを作成する。
  3. オーナーのアカウントでJWTを作成し、メンバーのアカウントを操作する。←こちらが一番おすすめ!

一つずつ解説していきたいと思います。

解決策①:新しい別のアカウントを作成し、そのアカウントでJWTを作成する。

こちらが一番簡単なやり方です。
新しい別のアカウントを作成し、オーナーと紐付けなければ、そのアカウントでJWTを作成できます。
ただ、勝手にアカウントを作成してJWTを作ることを許可してくれる会社はなかなかないはずです。
その時はこの方法が使えませんので、次の解決策②を試してみましょう。

解決策②:メンバーのアカウントをオーナーから切り離してからJWTを作成する。

こちらは文字通りです。
「オーナーと紐づいているなら、それを外してしまえ」という力技ですね。
実際のやり方はこちらの「アカウントからユーザーをリンク解除する」の見出しの記事をご覧ください。
ただ、前述の通り会社のオーナーアカウントに社員のメンバーアカウントを紐づけて管理している会社であれば、それを切り離すことは許されない場合がほとんどだと思います。
そいう行った場合は次の最終手段を取ります。

解決③:オーナーのアカウントでJWTを作成し、メンバーのアカウントを操作する。

実はオーナーのアカウントでJWTを発行し、その後でメンバーのアカウントのユーザーIDを取得してZoomを操作することができます。
Zoom APIを使う理由として「他のアプリケーションで新規Zoomミーティングのスケジュールをしたい」というのが一番多いニーズだと思いますが、それをGASで実現するためのコードは下記の通りです。

function getZoomAccessToken() {
  var ZOOM_API_KEY = '';//API KEYを入力
  var ZOOM_API_SECRET = '';//API SECRETを入力

  var header = { alg: 'HS256', typ: 'JWT' };
  var payload = {
    iss: ZOOM_API_KEY,
    exp: Date.now() + 1800,//時間設定
  };

  // ヘッダーとペイロードをコード化
  var jsonHeader = JSON.stringify(header);
  var encodedHeader = Utilities.base64Encode(jsonHeader);
  var jsonPayload = JSON.stringify(payload);
  var encodedPayload = Utilities.base64Encode(jsonPayload);

  // 署名を符号化した後にコード化
  var signatureHMAC = Utilities.computeHmacSha256Signature(`${encodedHeader}.${encodedPayload}`, ZOOM_API_SECRET);
  var encodedSignature = Utilities.base64Encode(signatureHMAC);

  // 戻り値にTokenを設定
  return `${encodedHeader}.${encodedPayload}.${encodedSignature}`;
}

function getZoomUserId() {
  var request = UrlFetchApp.fetch('https://api.zoom.us/v2/users/', {
    method: 'GET',
    contentType: 'application/json',
    headers: { Authorization: `Bearer ${getZoomAccessToken()}` },
  });
  var users = JSON.parse(request.getContentText());
  return users.users[0].id;
}

function createZoomMeeting() {  
  var meetingOptions = {
  'topic':'hoge',
  'type': '2',//ミーティングのタイプを入力。1が即時で2が予約。
  'start_time': '2022-08-16T11:30:00',//開始時刻を入力
  'duration': '120',//ミーティングの時間を設定
  'timezone': 'Asia/Tokyo',
  'password': '',//パスワードを設定
  'agenda': '',
  'settings': {
    'host_video': 'true',//ホストのビデオをオンにするか
    'participant_video': 'true',//参加者のビデオをオンにするか
    'cn_meeting': 'false',//ホストが中国からか
    'in_meeting': 'false',//ホストがインドからか
    'join_before_host': 'false',//ホストより前に参加者がミーティングに参加できるようにするかどうか
    'mute_upon_entry': 'false',//入室時にミュートにするかどうか
    'watermark': 'false',//画面共有時に透かしを加えるかどうか
    'use_pmi': 'false',
    'approval_type': '0',//参加者の入室を許可する方法
    'registration_type': '1',
    'audio': 'both',//参加者がどういった手段でミーティングの音声に参加するか
    'auto_recording': 'none',//ミーティングの自動録画設定
    'enforce_login': 'false',
    'enforce_login_domains': '',
    'waiting_room': 'true',//参加者を一度待機させるかどうか
    'alternative_hosts': '',
    'global_dial_in_countries': [
      ''
    ],
    'registrants_email_notification': 'false'
    }
  };

  var request = UrlFetchApp.fetch(
    `https://api.zoom.us/v2/users/${getZoomUserId()}/meetings`,
    {
      method: 'POST',
      contentType: 'application/json',
      headers: { Authorization: `Bearer ${getZoomAccessToken()}` },
      payload: JSON.stringify(meetingOptions),
    }
  );

  var cont = JSON.parse(request.getContentText('UTF-8'));
  Logger.log(cont['join_url']);
  Logger.log(cont['password']);
}

上記のコードでは、getZoomUserId関数でアカウントのユーザーIDを取得しているのですが、ここで新規ZoomミーディングをスケジュールさせるメンバーアカウントのユーザーIDが吐き出されるように設定すればいいのです。

もしオーナーアカウントのAPI KEYでgetZoomUserId関数を動かすと、31行目の変数usersの中にメンバーや管理者も含めた情報が配列として格納されます。あとはそれを32行目のコードで指定してあげればいいだけです。
ちなみに32行目のコード(return users.users[0].id;)の0の部分を1や2などに変更すれば、配列の中にある各アカウントのユーザーIDの指定を切り替えることができます。

こちらの方法であれば、オーナーアカウントからメンバーアカウントを切り離す必要はないため、ほとんどの会社で採用されている方法になるのではないかと思います。

まとめ

今回はZoom APIでJWTを作成できない時の原因と3つの解決方法についてご紹介しました。
もし同じ問題で困った時は、ぜひ上記の方法を試して欲しいと思います。
では、快適なZoomライフをお過ごしください!

«
»