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) にて、Google Workspace Developer Hub にお持ちの Google アカウントでログインします。

  2. 「新規スクリプト」をクリックして、GAS のエディターを表示します。

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

  4. ライブラリのスクリプト ID「1B7FSrk5Zi6L1rSxxTDgDEUsPzlukDsi4KGuTMorsTQHhGBzBkMun4iDF」を入力し、「追加」ボタンでライブラリを追加します。
    最新のバージョンを選択して、設定を保存します。(詳細は こちら (External link) を参照してください)

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

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

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

https://script.google.com/macros/d/SCRIPT_ID/usercallback/

今回作成した SCRIPT_ID は、GAS エディターのファイルメニューの「プロジェクトのプロパティ」より、取得します。

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

  • クライアント 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
/*
* Google Apps Script から、OAuth 2.0 を使って、kintone API を利用する
* Copyright (c) 2019 Cybozu
*
* Licensed under the MIT License
*/

/*
* 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://{サブドメイン名}.cybozu.com/oauth2/authorization')// 認可エンドポイント
    .setTokenUrl('https://{サブドメイン名}.cybozu.com/oauth2/token')// トークンエンドポイント

    // kintone のクライアント ID およびクライアントシークレットを設定
    .setClientId('{クライアントID}') // OAuth クライアント ID
    .setClientSecret('{クライアントシークレット}') // 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://{サブドメイン名}.cybozu.com/k/v1/record.json?app={アプリ ID}&id={レコード番号}';
  // 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://{サブドメイン名}.cybozu.com/oauth2/authorization')// 認可エンドポイント
    .setTokenUrl('https://{サブドメイン名}.cybozu.com/oauth2/token')// トークンエンドポイント

    // kintone のクライアント ID およびクライアントシークレットを設定
    .setClientId('{クライアントID}') // OAuth クライアント ID
    .setClientSecret('{クライアントシークレット}') // 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://{サブドメイン名}.cybozu.com/k/v1/record.json?app={アプリID}&id={レコード番号}';
// 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 エディターの「表示」メニューから、「マニフェスト ファイルの表示」を選択します。

  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 のスクリプトエディターの「公開」メニューより、「ウェブアプリケーションとして導入」を選択します。

プロジェクトバージョンに「New」を選択し、「導入」ボタンをクリックします。

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 は、2019 年 02 月版 kintone で動作を確認しています。