Google Apps ScriptからOAuth 2.0でkintone APIを利用する

目次

はじめに

cybozu.com共通管理メニュー内の外部連携でOAuthクライアントの設定ができます。
今回は、Google Apps Script(以下GAS)の チュートリアル (External link) を参考に、OAuth 2.0の承認を経て、kintone APIでデータを取得するサンプルコードを作成します。
機能としては、kintone APIより取得したメッセージをGoogleドキュメントに書き込み、GmailでGoogleドキュメントへのリンクを送信するサンプルを作成します。
なお、コードを簡素化するため、OAuth 2.0認証にGASの ライブラリ (External link) を利用します。

cybozu.comのOAuthクライアントについてのドキュメントは こちら です。

開発手順

  1. kintoneアプリの開発
  2. OAuth2ライブラリの設定
  3. OAuthクライアントの設定
  4. GASアプリの開発
  5. GASアプリのOAuthスコープの設定
  6. 動作確認

1. kintoneアプリの開発

画面を参考にGoogleドキュメントへ送信するメッセージを入力するフィールドを設定します。

フィールドの種類 フィールド名 フィールドコード
文字列(1行) メッセージ message

「フォームを保存」し、「アプリを更新」します。

kintoneアプリの設定は以上です。

2. OAuth2ライブラリの設定

  1. Google Apps Script (External link) にて、Apps Scriptダッシュボードにお持ちのGoogleアカウントでログインします。

  2. 「新しいプロジェクト」または「Apps Script」のカードをクリックして、GASのエディターを表示します。

  3. プロジェクト名を入力し、「リソース」メニューから、「ライブラリ」を選択します。

  4. apps-script-oauth2 (External link) のスクリプトID「1B7FSrk5Zi6L1rSxxTDgDEUsPzlukDsi4KGuTMorsTQHhGBzBkMun4iDF」を入力し、「検索」ボタンをクリックします。

    最新のバージョンを選択して、「追加」ボタンでライブラリを追加します。
    ライブラリの詳細は apps-script-oauth2 (External link) を参照してください。

3. OAuthクライアントの設定

kintoneのcybozu.com共通管理ページより、外部連携の設定画面にて、「OAuthクライアントの追加」をクリックします。

リダイレクトエンドポイントは次の形式で設定します。

1
https://script.google.com/macros/d/スクリプトID/usercallback

スクリプトIDは、「プロジェクトの設定」メニュー内で確認できます。

クライアント名とリダイレクトエンドポイントを入力し、「保存」すると以下の情報が、自動生成されます。

  • クライアントID
  • クライアントシークレット
  • 認可エンドポイント
  • トークンエンドポイント

「連携利用ユーザーの設定」をクリックし、API利用を許可するユーザーを選択し、設定を保存します。

以上でOAuthクライアントの設定は終了です。

4. GASアプリの開発

GASのアプリは、こちらの チュートリアル (External link) を参考に開発します。

アプリの機能

  1. OAuth 2.0でkintone APIへのアクセスを認証する。
  2. kintone APIより、メッセージを取得する。
  3. 「Hello, World!」という名前で、Googleドキュメントを作成する。
  4. Googleドキュメントのボディーにkintoneからのメーセージを書き込む。
  5. GmailでGoogleドキュメントへのリンクを送信する。

OAuth 2.0の認証に関しましては、上記で設定した OAuth2 for Apps Script (External link) というGASのライブラリを利用します。

4.1. GASのコーディング

以下を参考にコーディングします。

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
/*
* Google Apps Scriptから、OAuth 2.0を使って、kintone APIを利用する
* Copyright (c) 2019 Cybozu
*
* Licensed under the MIT License
*/

const domain = 'sample.cybozu.com'; // サブドメイン
const clientId = 'XXXXXXXXXXXXXX'; // OAuthクライアントID
const clientSecret = 'XXXXXXXXXXXXXXXXXXXX'; // OAuthクライアントシークレット
const appId = '100'; // アプリID
const recordId = '1'; // レコード番号

/*
* kintoneへの承認リクエスト
*/
function doGet() {
  'use strict';
  const service = getService();
  if (service.hasAccess()) {
    createAndSendDocument(service.getAccessToken());
    return HtmlService.createHtmlOutput('Success');
  }
  // 承認されていない場合、承認リンクをHTMLページに表示
  const authorizationUrl = service.getAuthorizationUrl();
  const template = '<a href="' + authorizationUrl + '" target="_blank">Authorize</a>';
  return HtmlService.createHtmlOutput(template);
}

/**
 * OAuth 2.0 serviceのセットアップ
 */
function getService() {
  'use strict';
  // OAuth 2.0承認サービスの生成
  return OAuth2.createService('kintone')
    .setAuthorizationBaseUrl(`https://${domain}/oauth2/authorization`)// 認可エンドポイント
    .setTokenUrl(`https://${domain}/oauth2/token`)// トークンエンドポイント

    // kintoneのクライアントIDおよびクライアントシークレットを設定
    .setClientId(clientId) // OAuthクライアントID
    .setClientSecret(clientSecret) // OAuthクライアントシークレット

    // OAuth2.0承認後のコールバック関数名の設定
    .setCallbackFunction('authCallback')

    // 承認トークンを維持するプロパティーストアの設定
    .setPropertyStore(PropertiesService.getUserProperties())

    // kintone APIリクエストのスコープ設定
    .setScope('k:app_record:read'); // kintone APIのスコープ
}

/**
 * 最初のOAuth2承認の際のコールバック処理
 */
function authCallback(request) {
  'use strict';
  const service = getService();
  const authorized = service.handleCallback(request);
  if (authorized) {
    createAndSendDocument(service.getAccessToken());
    return HtmlService.createHtmlOutput('Success!');
  }
  return HtmlService.createHtmlOutput('Denied.');
}

/**
 * Googleドキュメントを作成し、そのリンクをメールで送信
 */
function createAndSendDocument(accessToken) {
  'use strict';
  // kintone APIのURLおよび、アプリID、レコード番号
  const appUrl = `https://${domain}/k/v1/record.json?app=${appId}&id=${recordId}`;
  // kintone APIの呼び出し
  const response = UrlFetchApp.fetch(appUrl,
  // ヘッダーにアクセストークンを設定
    {
      headers: {
        Authorization: 'Bearer ' + accessToken
      }
    }
  );
  const result = JSON.parse(response.getContentText());// レスポンスをJSON形式に変換

  // ログインユーザーのEメールアドレスを取得
  const email = Session.getActiveUser().getEmail();

  // 新規Googleドキュメントを 'Hello, world!' という名前で作成
  const doc = DocumentApp.create('Hello, world!');

  // Eメールの題目としてドキュメント名を取得
  const subject = doc.getName();

  // ドキュメントのボディーにkintone APIから取得したメッセージを追加
  doc.getBody().appendParagraph(result.record.message.value);
  // ドキュメントのURLを取得
  const docUrl = doc.getUrl();
  // ドキュメントのURLをEメールのボディーに追加
  const body = 'Link to your doc: ' + docUrl;

  // ドキュメントへのリンクをログインユーザーへEメール送信
  GmailApp.sendEmail(email, subject, body);
}
4.2. コードの解説
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
/*
* kintoneへの承認リクエスト
*/
function doGet() {
  'use strict';
  const service = getService();
  if (service.hasAccess()) {
    createAndSendDocument(service.getAccessToken());
    return HtmlService.createHtmlOutput('Success');
  }
  // 承認されていない場合、承認リンクをHTMLページに表示
  const authorizationUrl = service.getAuthorizationUrl();
  const template = '<a href="' + authorizationUrl + '" target="_blank">Authorize</a>';
  return HtmlService.createHtmlOutput(template);
}

doGet関数は、GASコードをのちほどWebアプリケーションとして実行した際、最初に自動で呼び出される関数です。
OAuth2.0認証サービスを生成し、すでに承認されていれば、アクセストークンを引き渡し、kintone APIよりデータを取得する関数を呼び出します。
まだ、認証されていない場合には、承認リンクをブラウザーに表示します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/**
 * OAuth 2.0 serviceのセットアップ
 */
function getService() {
  'use strict';
  // OAuth 2.0承認サービスの生成
  return OAuth2.createService('kintone')
    .setAuthorizationBaseUrl(`https://${domain}/oauth2/authorization`)// 認可エンドポイント
    .setTokenUrl(`https://${domain}.cybozu.com/oauth2/token`)// トークンエンドポイント

    // kintoneのクライアントIDおよびクライアントシークレットを設定
    .setClientId(cliendId) // OAuthクライアントID
    .setClientSecret(clientSecret) // OAuthクライアントシークレット

    // OAuth2.0承認後のコールバック関数名の設定
    .setCallbackFunction('authCallback')

    // 承認トークンを維持するプロパティーストアの設定
    .setPropertyStore(PropertiesService.getUserProperties())

    // kintone APIリクエストのスコープ設定
    .setScope('k:app_record:read'); // kintone APIのスコープ
}

OAuth2.0ライブラリを使って、OAuth2.0承認サービスを生成します。上記で設定したOAuthクライアントの各種情報を設定しています。

PropertiesService.getScriptProperties()にて、承認トークンの設定を保存するサービスの指定をしています。
スコープの値は、 kintoneのOAuthスコープ で確認してください。

コールバック関数は、authCallbackを指定します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
/**
 * 最初のOAuth2承認の際のコールバック処理
 */
function authCallback(request) {
  'use strict';
  const service = getService();
  const authorized = service.handleCallback(request);
  if (authorized) {
    createAndSendDocument(service.getAccessToken());
    return HtmlService.createHtmlOutput('Success!');
  }
  return HtmlService.createHtmlOutput('Denied.');
}

ブラウザーから承認リンクをクリックした場合にkintoneへ認可リクエストを送信した際に処理されるコールバック関数です。ライブラリ内で認可コードを取得して、アクセストークンを要求・取得する処理が実行されます。

承認されるとkintone APIを実行する関数を呼び出し、ブラウザーに「Success」と表示されます。
また、承認が拒否された場合には「Denied」が表示されます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
// kintone APIのURLおよび、アプリID、レコード番号
const appUrl = `https://${domain}/k/v1/record.json?app=${appId}&id=${recordId}`;
// kintone APIの呼び出し
const response = UrlFetchApp.fetch(appUrl,
  // ヘッダーにアクセストークンを設定
  {
    headers: {
      Authorization: 'Bearer ' + accessToken
    }
  }
);
const result = JSON.parse(response.getContentText());// レスポンスをJSON形式に変換

取得したアクセストークンをヘッダーに設定して、kintone APIでアプリのデータを取得します。URLには、アクセスしたいアプリのIDとレコード番号を含めて指定します。

取得したデータをJSON形式に変換します。

1
2
3
4
5
6
// 新規Googleドキュメントを 'Hello, world!' という名前で作成
const doc = DocumentApp.create('Hello, world!');
// ドキュメントのボディーにkintone APIから取得したメッセージを追加
doc.getBody().appendParagraph(result.record.message.value);
// ドキュメントのURLを取得
const docUrl = doc.getUrl();

Googleドキュメントを新規作成し、ボディーにkintoneから取得したデータを書き込みます。
その後、新規作成したGoogleドキュメントのURLを取得します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
// ログインユーザーのEメールアドレスを取得
const email = Session.getActiveUser().getEmail();

// Eメールの題目としてドキュメント名を取得
const subject = doc.getName();

// ドキュメントのURLをEメールのボディーに追加
const body = 'Link to your doc: ' + docUrl;

// ドキュメントへのリンクをログインユーザーへEメール送信
GmailApp.sendEmail(email, subject, body);

ログインしているユーザーのEメールアドレスを取得し、Eメールの題目として、ドキュメント名を指定します。
取得したドキュメントのURLをリンクとして、Eメールのボディーに追加します。

Gmailにて、ログインユーザーへドキュメントへのリンクをメール送信します。

5. GASアプリのOAuthスコープの設定

GASからGmailやGoogleドキュメントを利用するため、マニフェストファイルにOAuth Scopeを設定します。
参考: OAuth 2.0 Scopes for Google APIs (External link)

  1. GASエディターの「プロジェクト設定」メニュー内で、「『appsscript.json』マニフェスト ファイルをエディタで表示する」にチェックを入れます。

  2. 表示された「appsscript.json」を選択し、次の値を追加します。

    1
    2
    3
    4
    5
    6
    
    "oauthScopes": [
      "https://www.googleapis.com/auth/script.external_request",
      "https://www.googleapis.com/auth/userinfo.email",
      "https://www.googleapis.com/auth/documents",
      "https://www.googleapis.com/auth/gmail.send"
    ],
  3. 「プロジェクトを保存」アイコンをクリックして保存します。

6. 動作確認

GASのスクリプトエディター右上の「デプロイ」メニューより、「新しいデプロイ」を選択します。

「ウェブアプリ」を選択します。

「デプロイ」ボタンをクリックします。

Googleアカウントのデータへのアクセスを許可します。

GASを作成したGoogleアカウントを選択します。

次のような警告が表示される場合、「詳細」をクリック後、「(安全でないページ)に移動」をクリックし、続けます。

GASのGoogleアカウントへのアクセスを許可します。

ウェブアプリのURLをクリックします。

ブラウザーに表示された承認リンクをクリックします。

kintoneのログイン画面が表示されるので、ユーザー名とパスワードを入力してログインします。

OAuthクライアントのアクセスを許可します。

「Success!」が表示されます。 OAuthクライアントの承認を経て、スクリプトが実行されたことになります。

しばらくするとGmailが送信され、Googleドキュメントへのリンクをクリックしてkintoneアプリで設定したメッセージが表示されていれば、成功です。

まとめ

新たに導入された外部連携の機能で、外部アプリケーションからOAuth 2.0を使って、kintone APIへのアクセスができるようになりました。
これにより、OAuth2.0で安全にユーザーを認証し、外部アプリケーションからkintone APIを通じて、アプリのデータを取得できるようになりました。

OAuthクライアント

information

このTipsは、2024年7月版kintoneで動作を確認しています。