スプレッドシートとGoogle Apps Scriptでかんたんなクライアントアプリを作ってみる
前のセクションでは、Node.jsを用いてMoney Forwardの認可サーバーと連携するOAuthクライアントアプリケーションを構築する方法を紹介しました。 このチュートリアルでは、GoogleのアプリであるスプレッドシートとGoogle Apps Scriptを用いてクライアントアプリケーションを構築しながら、実装ポイントを解説していきます。
このチュートリアルはハンズオン形式で、Google Workspaceで実際にコードを書いて動作を確認しながら学べる内容になっています。OAuthクライアント機能の実装手順について、認可、アクセストークンの取得、アクセストークンが必要な保護されたAPIの呼び出し、トークンのリフレッシュ、トークンの取り消しまでを詳しく説明します。
1. 前提条件
Google Workspaceのアカウントを用意し、ログインしてください。 通常、Google Workspaceのアカウントがあれば、Google Apps Scriptとスプレッドシートを使用できます。 ただし、組織の管理者の設定によっては、Google Apps Scriptの使用が制限されている場合があります。 本チュートリアルを進める前に、ご利用の組織でスプレッドシートとGoogle Apps Scriptが使用可能であることをご確認ください。
また、本チュートリアルでは以下のライブラリを使用します。使い方は後述します。
- apps-script-oauth2 :バージョンや詳細な設定については、GitHubリポジトリのREADMEを参照してください。
注意: 本チュートリアルでは、Google Workspaceの基本的な操作については最小限の説明にとどめています。詳細な操作方法については、Googleの公式ドキュメントを参照してください。
2. プロジェクト構成の概要
次の機能を備えた簡易的なOAuth2アプリクライアントを構築します:
- 認可プロセスを開始する
- 認可成功後のコールバックを処理し、アクセストークンを取得する
- アクセストークンとリフレッシュトークンを取り消します。
- 保護されたAPIリソースにアクセスする
3. OAuth2 クライアントの実装
スプレッドシートの作成
以下のGoogle Workspaceの公式ドキュメントを参照し、スプレッドシートとスプレッドシートにバインドされたプロジェクトを作成してください。 プロジェクト名は任意の名前でかまいません。
スプレッドシートの設定
スプレッドシートに操作ボタンを配置します。 図形にスクリプトを割り当てることで、ボタンをクリックした際に特定の処理を実行できます。 本チュートリアルでは、すべての操作をボタンクリックで実行する方式を採用します。
スプレッドシートの挿入
メニューから図形描画
を選択し、任意の図形を3つ作成してください。
図形描画について詳細はこちらをご確認ください。
また、APIの実行結果とトークン情報を表示するためのセルを用意します。
例えばこのように配置します。
OAuth2クライアントの設定
認可プロセスを開始する前に、OAuth2クライアントの情報を設定します。クライアントID、クライアントシークレット、認可サーバーURLなどの必須情報を以下のように設定します。 この設定は、Google Apps Scriptに記載します。
Google Apps Scriptプロジェクトを作成すると、自動的にコード.gs
というファイルが生成されます。
このファイルに設定やソースコードを記述していきます。
なお、初期状態で作成されるmyFunction
という関数は不要なので削除してください。
const CLIENT_ID = 'YOUR CLIENT_ID'; // OAuth2クライアントのクライアントID
const CLIENT_SECRET = 'YOUR CLIENT_SECRET'; // OAuth2クライアントのクライアントシークレット
const AUTHORIZATION_SERVER = 'https://api.biz.moneyforward.com'; // OAuth2認可サーバーの基本URL
次に、アクセス権限の範囲(スコープ)を設定します。 本チュートリアルでは事業者情報へのアクセスを例としているため、以下のスコープを設定します。 実際のアプリケーション開発時には、必要なアクセス権限に応じて適切なスコープを設定してください。
const scopes = ['mfc/admin/office.read'];
注意: スコープの設定を誤った場合、認可処理自体は成功しますが、APIリクエスト時に以下のようなエラーが発生します。
Request failed for https://bizapis.moneyforward.com returned code 403. Truncated server response: {"message":"forbidden"}
次に、OAuth2クライアントのインスタンスを作成します。 認可方式によって設定方法が異なりますので、以下の2つの方法から適切なものを選択してください。
CLIENT_SECRET_POST認証方式の場合:
const driveService = getDriveService_BASIC_POST();
function getDriveService_POST() {
return OAuth2.createService('MFAPI')
.setAuthorizationBaseUrl(AUTHORIZATION_SERVER + '/authorize')
.setTokenUrl(AUTHORIZATION_SERVER + '/token')
.setClientId(CLIENT_ID)
.setClientSecret(CLIENT_SECRET)
.setCallbackFunction('authCallback') // 認可完了後のコールバック関数名(後述)
.setScope(scopes)
.generateCodeVerifier()
.setPropertyStore(PropertiesService.getUserProperties()); // 認証トークンを永続化するためのプロパティ ストアを設定します。
}
CLIENT_SECRET_BASIC認証方式の場合:
const driveService = getDriveService_BASIC();
function getDriveService_BASIC() {
return OAuth2.createService('MFAPI')
.setAuthorizationBaseUrl(AUTHORIZATION_SERVER + '/authorize')
.setTokenUrl(AUTHORIZATION_SERVER + '/token')
.setClientId(CLIENT_ID)
.setCallbackFunction('authCallback') // 認可完了後のコールバック関数名(後述)
.setScope(scopes)
.generateCodeVerifier()
.setGrantType('client_credentials')
.setTokenHeaders({
Authorization:
'Basic ' + Utilities.base64Encode(CLIENT_ID + ':' + CLIENT_SECRET),
})
.setPropertyStore(PropertiesService.getUserProperties()); // 認証トークンを永続化するためのプロパティ ストアを設定します。
}
詳細な説明:
CLIENT_ID
: Money Forwardによって提供されるクライアントの一意の識別子。CLIENT_SECRET
: クライアントシークレット。安全に保管してください。AUTHORIZATION_SERVER
: Money Forward認可サーバーの基本URL。
注意: このサンプルコードでは
CLIENT_ID
とCLIENT_SECRET
がハードコーディングされていますが、実際のアプリケーションでは、これらを安全な場所に保管する必要があります。
また、アプリケーションにリダイレクトURIを設定する必要があります。
Google Apps ScriptのプロジェクトIDを使用して、以下の形式で設定してください:
https://script.google.com/macros/d/{SCRIPT_ID}/usercallback
このリダイレクトURIは、Money Forwardのアプリポータルで設定する必要があります。 設定手順は以下の通りです。
- アプリポータルにログイン
アプリ開発 [開発者向け]
を選択- 対象のアプリケーションを選択
リダイレクトURI
の設定画面で上記のURIを登録
設定が完了したら、認可プロセスの実装に進みます。
A. 認可
まず、apps-script-oauth2ライブラリをインストールする必要があります。 インストールの手順は以下の通りです。
- Apps Scriptコードエディターを開きます
- メニューバーから
ライブラリ
横の+ボタンを選択します ライブラリを検索
テキストボックスに以下のスクリプトIDを入力します:1B7FSrk5Zi6L1rSxxTDgDEUsPzlukDsi4KGuTMorsTQHhGBzBkMun4iDF
検索
ボタンをクリックします- バージョンを選択します(通常は最新バージョンを推奨します)
追加
ボタンをクリックします
注意: ライブラリの詳細な使用方法については、公式ドキュメントを参照してください。
次に、認可プロセスを開始するための関数を実装します。 この関数は、ユーザーをマネーフォワード クラウドの認可サーバーにリダイレクトします。
function startAuthorization() {
if (!driveService.hasAccess()) {
const authorizationUrl = driveService.getAuthorizationUrl();
const script = `
<script>
window.open('${authorizationUrl}', '_blank').focus();
</script>
<p>自動で別タブが開きます</p>
<p>別タブでの認可が完了したらこのダイアログは閉じてください</p>
`;
const html = HtmlService.createHtmlOutput(script);
SpreadsheetApp.getUi().showModalDialog(html, '認可を開始します');
} else {
const html = HtmlService.createHtmlOutput('認可済みです');
SpreadsheetApp.getUi().showModalDialog(html, '認可状態');
}
}
この関数は、未認可の場合は認可URLを新しいタブで開きます。 認可済みの場合は、その旨を画面で表示します。
B. アクセスおよびリフレッシュトークンの取得
authCallback
関数は、認可サーバーからのリダイレクトを受け取るコールバック関数です。
この関数のなかで、認可サーバーからアクセストークンとリフレッシュトークンを取得します。
トークンはプロパティストアに自動的に保存されるため、本番環境でこの処理は不要です。
本チュートリアルでは、学習のためにトークンの情報をスプレッドシートのA4とA5セルに表示するようにしています。
function authCallback(request) {
const isAuthorized = driveService.handleCallback(request);
const sheet = SpreadsheetApp.getActiveSheet();
try {
if (isAuthorized) {
const token = driveService.getToken();
sheet.getRange('A4').setValue('Access Token: ' + token.access_token);
sheet.getRange('A5').setValue('Refresh Token: ' + token.refresh_token);
sheet.getRange('A14').setValue('');
return HtmlService.createHtmlOutput(
'認可が完了しました。このタブは閉じてください。',
);
} else {
sheet
.getRange('A4')
.setValue('保持しているトークンはありません / No token available');
sheet.getRange('A5').setValue('');
sheet.getRange('A14').setValue('');
return HtmlService.createHtmlOutput(
'認可が拒否されました。このタブは閉じてください。',
);
}
} catch (error) {
console.error('認可処理中にエラーが発生しました:', error);
sheet.getRange('A4').setValue('認可処理中にエラーが発生しました');
sheet.getRange('A5').setValue('');
sheet.getRange('A14').setValue('');
return HtmlService.createHtmlOutput(
'認可処理中にエラーが発生しました。エラーの詳細はログを確認してください。',
);
}
}
C. 保護されたAPIの呼び出し
/office
ルートでアクセストークンを使用して保護されたリソースにアクセスします。このサンプルコードでは事業者情報の取得APIの呼び出しを例にしていますが、要件に応じて必要なAPI呼び出しを実装してください。
取得した結果はスプレッドシートのA14に表示するようにしています。
function showOffice() {
if (!driveService.hasAccess()) {
const html = HtmlService.createHtmlOutput(
'認可が必要です。先に認可を行ってください。',
);
SpreadsheetApp.getUi().showModalDialog(html, '認可が必要です');
return;
}
try {
const response = UrlFetchApp.fetch(
'https://bizapis.moneyforward.com/admin/office',
{
headers: {
Authorization: 'Bearer ' + driveService.getAccessToken(),
},
},
);
const myJson = JSON.parse(response);
const sheet = SpreadsheetApp.getActiveSheet();
sheet.getRange('A14').setValue(myJson);
// トークン情報を更新
const token = driveService.getToken();
sheet.getRange('A4').setValue('Access Token: ' + token.access_token);
sheet.getRange('A5').setValue('Refresh Token: ' + token.refresh_token);
} catch (error) {
console.error('API呼び出しに失敗しました:', error);
const sheet = SpreadsheetApp.getActiveSheet();
sheet
.getRange('A14')
.setValue('API呼び出しに失敗しました: ' + error.toString());
const html = HtmlService.createHtmlOutput(
'API呼び出しに失敗しました。エラーの詳細はスプレッドシートのA14セルを確認してください。',
);
SpreadsheetApp.getUi().showModalDialog(html, 'エラー');
}
}
詳細な説明:
- トークンの確認:
hasAccess
で有効なアクセストークンを含むことを確認し、不足している場合はユーザーにログインを促します。 - APIリクエストの構築: 保護されたリソースにアクセスするため、リクエストヘッダーにアクセストークンを含めます。
- 最終応答: 成功した場合はデータを解析して返却し、失敗した場合はエラーを記録します。
今回使用したライブラリはリフレッシュを自動的に行ってくれるため、明示的にリフレッシュする必要はありません。
D. トークンの取り消し
トークンを取り消してセキュリティを強化します。これはオプションの操作です。
function revokeToken() {
try {
driveService.reset();
const sheet = SpreadsheetApp.getActiveSheet();
sheet.getRange('A4').setValue('');
sheet.getRange('A5').setValue('');
sheet.getRange('A14').setValue('');
const html =
HtmlService.createHtmlOutput('トークンの取り消しが完了しました');
SpreadsheetApp.getUi().showModalDialog(html, '成功');
} catch (error) {
console.error('トークンの取り消しに失敗しました:', error);
const html = HtmlService.createHtmlOutput(
'トークンの取り消しに失敗しました。エラーの詳細はログを確認してください。',
);
SpreadsheetApp.getUi().showModalDialog(html, 'エラー');
}
}
E. 図形に関数を紐づける
スプレッドシートから簡単に関数を呼び出せるように、図形に関数を割り当てます。 割り当て手順は以下の通りです。
- 図形を選択します
- 図形の右端にある縦3点のメニューをクリックします
スクリプトを割り当て
を選択します- 割り当てたい関数名を入力して確定します
以下の関数をそれぞれの図形に割り当ててください。
- 認可開始 / Start Authorize
startAuthorization
- トークンを取り消し / Revoke tokens
revokeToken
- APIを呼び出し、保護されたリソースを取得 / Call API to fetch protected resource
showOffice
注意: 誤って関数を割り当ててしまった場合、通常のクリックでスクリプトが実行されてしまいます。 図形を右クリックで選択すると、メニューが表示され設定を変更できます。
4. テストと検証
以下の手順でテストを実施してください。 なお、はじめて実行する場合や、時間が経過した場合は、Googleから以下のような認可を求める画面が表示されることがあります。その場合は、画面に従い認可してください。
-
認可の実行:
- 認可開始 / Start Authorizeボタンをクリックします
- 別タブで認可画面が表示されます
- ログインしていない場合は、ログイン画面が表示されます
- 適切なアカウントでログインしてください
- 必要な権限を確認し、
許可
をクリックします
-
APIの呼び出し:
- APIを呼び出し、保護されたリソースを取得 / Call API to fetch protected resourceボタンをクリックします
- API呼び出しが成功し、データが表示されることを確認します
-
トークンの取り消し:
- トークンを取り消し / Revoke tokensボタンをクリックします
- トークンが正常に取り消されることを確認します
5. まとめ
本チュートリアルでは、Google Apps Scriptおよびスプレッドシートを使用してMoney Forwardの認可サーバーと連携するOAuth2クライアントアプリケーションの実装方法を学びました。そして以下の主要な実装ポイントをカバーしました。
- OAuth2クライアントの設定: クライアントID、クライアントシークレット、リダイレクトURIなどの基本設定を行ないました。
- 認可プロセスの開始: ユーザーを認可サーバーにリダイレクトして認可コードを取得する手順を実装しました。
- アクセストークンとリフレッシュトークンの取得: 認可コードを使用してトークンを取得する方法を解説しました。
- 保護されたAPIの呼び出し: 取得したアクセストークンを使用して保護されたリソースにアクセスする方法を説明しました。
- トークンの取り消し: セキュリティ強化のためのトークン取り消し方法を紹介しました。
これらの実装ポイントを通じて、OAuth2クライアントアプリケーションの基本的な流れとセキュリティ上の考慮事項を説明しました。
6. 次のステップ
このチュートリアルは実装ポイントについての理解を目的としているため、実際のアプリにはそのまま使用できるものではありません。実際のアプリに利用するためには、以下のような内容について検討することを推奨しています。
- アプリケーションにOAuth2クライアントを統合する。
client_id
,client_secret
を適切に保存する。- 取得したアクセストークンおよびリフレッシュトークンを適切に保存する。(サンプルコードから、トークンを表示する処理を消す)