Node.jsでGmailAPI認証設定

## 概要
- Gmailアプリを簡単に作成する方法を書いておく
- ほかのGoogleAPI系の参考になればなおよい

## Google Cloude上の操作
Google Cloud上の操作については、こまごまとしたUIの変更が速いため本記事では明確に扱わない。
参考までに、以下の記事を提供しておくがボタンが消失しているものもあるため注意が必要である。

https://dotstud.io/blog/gmail-api-from-nodejs/

:::note warn
クライアントIDを作成する際に「その他」がなくなっているため、本記事ではそこを **「WEBアプリケーション」** として進めていく
:::
:::note alert
リダイレクトurlを何かしら設定しないと後の認証が通らないため、**http://localhost** を設定する必要がある
:::


## ライブラリのインストール
適当なフォルダを準備したのち、必要なライブラリをインストールする
```
npm i googleapis google-auth-library --save
```
現在のバージョンは次のようになっている
    "google-auth-library": "^9.6.3",
    "googleapis": "^133.0.0"


## アクセストークンの取得・準備

https://dotstud.io/blog/gmail-api-from-nodejs/

参考サイトとは大幅にバージョンが違うため、若干修正が必要であるが大筋は変わらない。

```js
//getAndStoreToken.js
'use strict';

const fs = require('fs');
const readline = require('readline');
const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout,
});
const { promisify } = require('util');

const { google } = require('googleapis');
const { OAuth2Client } = require('google-auth-library');

//promisifyでプロミス化
const readFileAsync = promisify(fs.readFile);
const writeFileAsync = promisify(fs.writeFile);
const rlQuestionAsync = promisify(rl.question);

const SCOPES = [
  'https://www.googleapis.com/auth/gmail.send',
  'https://www.googleapis.com/auth/gmail.readonly',
];
const TOKEN_DIR = __dirname;
const TOKEN_PATH = TOKEN_DIR + '/gmail-nodejs-quickstart.json';

const main = async () => {
  const content = await readFileAsync(__dirname + '/client_secret.json');
  const credentials = JSON.parse(content); //クレデンシャル
  //認証
  const clientSecret = credentials.web.client_secret; // ここでjsonを読み込む際の構造に変化がある
  const clientId = credentials.web.client_id;
  const redirectUrl = credentials.web.redirect_uris[0];
  const oauth2Client = new OAuth2Client(clientId, clientSecret, redirectUrl);

  //get new token
  const authUrl = oauth2Client.generateAuthUrl({
    access_type: 'offline',
    scope: SCOPES,
  });

  console.log('Authorize this app by visiting this url: ', authUrl);

  rl.question('Enter the code from that page here: ', (code) => {
    rl.close();

    oauth2Client.getToken(code, async (err, token) => {
      if (err) {
        console.log('Error while trying to retrieve access token', err);
        return;
      }

      oauth2Client.credentials = token;

      try {
        fs.mkdirSync(TOKEN_DIR);
      } catch (err) {
        if (err.code != 'EEXIST') throw err;
      }

      await writeFileAsync(TOKEN_PATH, JSON.stringify(token));
      console.log('Token stored to ' + TOKEN_PATH);
    });
  });
};

main();
```

## アクセストークンの取得・実行
```sh
node ファイル名.js
Authorize this app by visiting this url: https://hogehoge...
Enter the code from that page here:
```
このように認証用のURLが発行されるためリンクを踏み、指示通りに実行する。
```
# 認証情報を持ったURLにリダイレクトされるため、認証情報をコピーする
http://localhost/?code=4/hogehogefugafygapiyopiyoetocetora&scope=https://www.googleapis.com/auth/gmail.readonly%20https://www.googleapis.com/auth/gmail.send
```

この時次の部分が認証情報である
**4/hogehogefugafygapiyopiyoetocetora**

これをコピーして貼り付け、Enterを押すことでアクセストークンを取得することができる

## 試しの実行
```js
//getLabels.js
'use strict';

const fs = require('fs');
const { promisify } = require('util');
const { google } = require('googleapis');
const { OAuth2Client } = require('google-auth-library');
const gmail = google.gmail('v1');

//promisifyでプロミス化
const readFileAsync = promisify(fs.readFile);
// 直接指定しなければ動かないため、直接指定した
// const gmailListLabesAsync = promisify(gmail.users.labels.list); //Gmailのラベル一覧

const TOKEN_DIR = __dirname;
const TOKEN_PATH = TOKEN_DIR + '/gmail-nodejs-quickstart.json'; //アクセストークンのファイルを指定

const main = async () => {
  //クレデンシャル情報の取得
  const content = await readFileAsync(__dirname + '/client_secret.json');
  const credentials = JSON.parse(content); //クレデンシャル
  console.log(credentials);

  //認証
  const clientSecret = credentials.installed.client_secret;
  const clientId = credentials.installed.client_id;
  const redirectUrl = credentials.installed.redirect_uris[0];
  const oauth2Client = new OAuth2Client(clientId, clientSecret, redirectUrl);
  const token = await readFileAsync(TOKEN_PATH);
  oauth2Client.credentials = JSON.parse(token);

  //API経由でシートにアクセス
  const response = await gmail.users.labels.list({
    auth: oauth2Client,
    userId: 'me',
  });
  //結果を表示
  console.log(response.data);
};

main();
```
## 動作上の苦労等
https://dotstud.io/blog/gmail-api-from-nodejs/

参考にしたドキュメントの下のほうに多数苦労が書いてあるため参考にするとよい

## 公式ドキュメント
言うまでもないが、最低限の動作確認が済めば公式ドキュメントを参考にすることを進める

https://developers.google.com/gmail/api/reference/rest/v1/users?hl=ja


## まとめ
バージョンの違いもあったが、流石のgoogleというか情報も多く比較的容易に動かすことができた。