Closed4

Google Calender API を使って予定追加(サービスアカウント編 Part1)

yoshida567yoshida567

サービスアカウントを払い出して Calender を操作

参考
https://qiita.com/Cayden_Madden/items/a679e0ab2a55d172fb1d

サービスアカウントの作成

clender-edit と言う名前でサービスアカウントを作成した。以下はいずれも空欄。

  • このサービス アカウントにプロジェクトへのアクセスを許可する (省略可)
  • ユーザーにこのサービス アカウントへのアクセスを許可 (省略可)

Google Calender 側での権限付与

Google Calender で操作したいアカウントを開き「予定の変更」権限を付与する。

yoshida567yoshida567

↑の手続きの後、以下のコードでカレンダーに予定を追加できるようになる。

index.js
const { google } = require('googleapis');
const fs = require('fs');

const key = JSON.parse(fs.readFileSync('keys/serviceaccount/service-account-key.json'));
const calendar = google.calendar('v3');

const SCOPES = ['https://www.googleapis.com/auth/calendar'];

const jwtClient = new google.auth.JWT(
    key.client_email,
    null,
    key.private_key,
    SCOPES
);

jwtClient.authorize((err, tokens) => {
    if (err) {
        console.error('認証エラー:', err);
        return;
    }

    console.log('認証成功');

    // 予定の情報
    const event = {
        'summary': 'テスト予定',
        'description': 'これはテストです。',
        'start': {
            'dateTime': '2024-03-18T13:00:00',
            'timeZone': 'Asia/Tokyo',
        },
        'end': {
            'dateTime': '2024-03-18T15:00:00',
            'timeZone': 'Asia/Tokyo',
        },
    };

    calendar.events.insert({
        auth: jwtClient,
        calendarId: 'カレンダーを操作したいアカウント@gmail.com', 
        resource: event,
    }, (err, res) => {
        if (err) {
            console.error('予定の作成中にエラーが発生しました:', err);
            return;
        }
        console.log('予定が作成されました:', res.data.htmlLink);
    });
});
yoshida567yoshida567

上記コードでは invite ができない

このコードを使えばサービスアカウントで適当なユーザーを invite できて、サービスアカウント中心の運用ができる!個人のメアド中心の運用じゃないから長期運用でも安心!
...と思ったのだが、以下のようにコードを書くとエラーになってしまう。

  • 予定の作成者は primary = サービスアカウント
  • attendee に inviteしたいアカウントを追加
const { google } = require('googleapis');
const fs = require('fs');

const key = JSON.parse(fs.readFileSync('keys/serviceaccount/service-account-key.json'));
const calendar = google.calendar('v3');

const SCOPES = ['https://www.googleapis.com/auth/calendar'];

const jwtClient = new google.auth.JWT(
    key.client_email,
    null,
    key.private_key,
    SCOPES
);

jwtClient.authorize((err, tokens) => {
    if (err) {
        console.error('認証エラー:', err);
        return;
    }

    console.log('認証成功');

    // 予定の情報
    const event = {
        'summary': 'テスト予定',
        'description': 'これはテストです。',
        'start': {
            'dateTime': '2024-03-18T13:00:00',
            'timeZone': 'Asia/Tokyo',
        },
        'end': {
            'dateTime': '2024-03-18T15:00:00',
            'timeZone': 'Asia/Tokyo',
        },
        attendees: [
            {
                email: 'inviteしたいアカウント@gmail.com'
            }
        ]
    };

    calendar.events.insert({
        auth: jwtClient,
        calendarId: 'primary', // カレンダーID。primary はデフォルトのカレンダーを表します。
        resource: event,
    }, (err, res) => {
        if (err) {
            console.error('予定の作成中にエラーが発生しました:', err);
            return;
        }
        console.log('予定が作成されました:', res.data.htmlLink);
    });
});

エラーの内容は次。

  code: 403,
  errors: [
    {
      domain: 'calendar',
      reason: 'forbiddenForServiceAccounts',
      message: 'Service accounts cannot invite attendees without Domain-Wide Delegation of Authority.'
    }
  ]

エラーの理由

ChatGPT に聞いてみた結果は次。

サービスアカウントは「Domain-Wide Delegation of Authority(ドメイン全体の権限委任)」なしで参加者を招待することができません。

「サービスアカウント」には「ドメイン全体の委任」設定項目があるので、これをONにすればよいと思われるが、「ドメイン全体の委任」がそもそもGSuitの設定なので、GSuitを使っていなければうまくいかない。

このスクラップは2024/03/17にクローズされました