# 🕊️「舞いカレンダー」が舞い始めた日 〜音声カレンダーとGoogle連携の迷宮突破記録〜
AIが作ってくれた… 実際の自分はもっと痩せてるけどな…
はじめに
山口県の田園地帯で、無農薬米を育てながら、早朝はスーパーでアルバイト。日中は個人開発者として、Android/Webアプリ「音声カレンダー」を独学で開発・運用しています。このアプリは、音声入力で予定を登録できる“自分だけの予定帳”として、日々進化を続けています。
今回の挑戦は、Googleカレンダーとの連携機能の実装。予定が「舞い込む」ように、音声カレンダーとGoogleが手を取り合う瞬間を目指しました。
使用技術と構成
Node.js(v22.12.0)
Express
Google Calendar API v3
OAuth2 認証(デスクトップアプリ用)
`token.json` に認証情報を保存
`server.js` にAPI連携処理を実装
認証情報(実際に使用したもの)
const oAuth2Client = new google.auth.OAuth2(
'*******************.apps.googleusercontent.com', // クライアントID
'GOCSPX-****************************', // クライアントシークレット
'urn:ietf:wg:oauth:2.0:oob' // デスクトップアプリ用リダイレクトURI
);`token.json` の内容(取得成功時)
{
"access_token": "ya29.a0AQQ_BDSB0hpM-...",
"refresh_token": "1//0ez2KjAKorWLoCgYIARAAGA4SNwF-...",
"scope": "https://www.googleapis.com/auth/calendar",
"token_type": "Bearer",
"refresh_token_expires_in": 604799,
"expiry_date": 1757917487404
}完成した `server.js`(抜粋)
const fs = require('fs');
const { google } = require('googleapis');
const express = require('express');
const app = express();
const PORT = 8080;
app.use(express.json());
app.use(express.static('public'));
const credentials = JSON.parse(fs.readFileSync('token.json'));
const oAuth2Client = new google.auth.OAuth2(
'*******************.apps.googleusercontent.com',
'GOCSPX-****************************',
'urn:ietf:wg:oauth:2.0:oob'
);
oAuth2Client.setCredentials(credentials);
// 予定追加と取得のAPI処理(省略)トラブルと突破
❌ `unauthorized_client`
→ 原因:古いクライアントIDで `token.json` を使っていた
→ 解決:新しい「デスクトップアプリ」用のIDとシークレットで再認証
❌ `No access, refresh token...`
→ 原因:`setCredentials()` の呼び出し順序が不適切だった
→ 解決:`oAuth2Client` を定義した直後に `setCredentials()` を呼び出すように修正
✅ 成功の瞬間
Googleカレンダーに「テスト」という予定が表示されたとき、思わず「舞った!」と叫びました。

