SlackのOAuthフローをDockerを使ってPoCする

## 経緯
[前回](https://qiita.com/tenda_ryo_y/items/8e16f0b508170f9ab230) 、ChatworkのOAuthフローをDockerで作ってみました。実はSlackに対しても同様の調査をする必要がありましたので、今回はその環境を使ってSlackのOAuthフローを作っていきたいと思います。使用するSlack APIのバージョンは**v2**です。
## 準備
### Slack app directory から Appの作成
SlackでOAuthを行うためにはまず、Slack Appを作る必要があります。
テスト用に作成したWorkspaceにAppを作っていきます。

まだ１つもAppが存在しない場合はこのような表示になっていますので、**Create an App**をクリックしましょう。
![スクリーンショット_2021-07-28_15.52.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2221418/18935c42-a795-c367-d955-a748459e59d4.png)
Appの名称を入力して、作成先のWorkspaceを選択します。
ここで入力した名称は第三者の目に触れる場所に表示されるので、正式な名称を入力ましょう。今回はPoCなので適当に名前をつけました。
![スクリーンショット_2021-07-28_15_45_42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2221418/c0ed2662-6025-1755-868d-c07e4e27ee27.png)
Appが作成されるとOAuth認証に必要な**Client ID**や**Client Secret**が発行されます。
![スクリーンショット_2021-07-28_15_46_09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2221418/0f1bb77c-03e8-664b-08d2-dcbbc93f2fcf.png)
### OAuth認証の設定
Appが作成されたらAppにOAuth認証の設定を施します。
左のメニューから **OAuth & Permissions** をクリックします。
![スクリーンショット_2021-07-28_15.48.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2221418/7720f50a-8e53-675b-0d5e-a1ca9d65ddc9.png)
いくつかある設定項目の中の **Redirect URLs** に OAuth認証に使用するリダイレクトURLを設定します。/oauthは既にChatwork検証時に使用してしまったので、 https://localhost:3443/oauth_slack というURLにしました。
![スクリーンショット_2021-07-28_15.48.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2221418/5ef02a99-dea7-4b40-7f5e-0f3e71f783cd.png)
OAuth認証後にメッセージのテスト送信を行うので、Bot用のScopes（権限）に **chat:write** を追加します。
Slack API v1では認証URLにScopeを指定すればOKでしたが、v2ではこちらにも権限を設定しないと認証URLにアクセスした際にエラーになりました。
![スクリーンショット_2021-07-29_13.14.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2221418/99e43a7d-6496-bb7d-5009-4c19e77e27b5.png)
### WorkspaceのチャンネルにAppをインストールする
指定したチャンネルIDにメッセージを送信するには、チャンネルにAppがインストールされている必要があります。この手続を行わないと、API実行時に **not_in_channel** というエラーが発生します。
![スクリーンショット_2021-07-28_17_20_22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2221418/ae6580d3-044d-902f-f4ce-aa2d246c9f7a.png)
インテグレーションタブを選択して「アプリを追加する」をクリックします。
![スクリーンショット_2021-07-28_17_19_34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2221418/8e85361c-0364-c2cb-3ee4-aad9fb79321b.png)
先ほど作成した **MyTest** がリストアップされていますので、「追加」をクリック。
![スクリーンショット_2021-07-28_17_19_47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2221418/dfe798e2-061e-4428-8f14-be393cc52756.png)
これでチャンネル **#general** へ **MyTest** がメッセージを送信できるようになりました。
## Express.jsにRouterを追加する
Express.jsの環境構築については[前回](https://qiita.com/tenda_ryo_y/items/8e16f0b508170f9ab230)の記事を参照してください。
前回構築したExpress.jsにSlack OAuth認証用のRouterを新しく追加します。
### OAuthリダイレクト用のRouterを追加
今回は /oauth_slack というパスを用意することにしました。
#### src/app.js
```javascript
...
var usersRouter = require('./routes/users');
var oauthRouter = require('./routes/oauth');
var oauthSlackRouter = require('./routes/oauthSlack'); // <- 追加
...
app.use('/users', usersRouter);
app.use('/oauth', oauthRouter);
app.use('/oauth_slack', oauthSlackRouter); // <- 追加
```
なお、今回はAccess Tokenの取得やメッセージの送信にSlackから提供されている [@slack/web-api](https://www.npmjs.com/package/@slack/web-api) を使用します。パッケージの使い方は[こちらのドキュメント](https://slack.dev/node-slack-sdk/web-api)を参照してください。
#### src/routes/oauthSlack.js

```javascript
const express = require('express');
const router = express.Router();
const { WebClient } = require('@slack/web-api');

router.get('/', async function (req, res, next) {
  let isSuccess = false;

  try {
    const wc = new WebClient();
    /**
     * Access Tokenを取得する
     */
    const resultToken = await wc.oauth.v2.access({
      client_id: process.env.SLACK_CLIENT_ID,
      client_secret: process.env.SLACK_CLIENT_SECRET,
      code: req.query.code,
    });
    console.log(resultToken);

    /**
     * テストメッセージを送信する
     */
    const resultMessage = await wc.chat.postMessage({
      token: resultToken.access_token,
      channel: process.env.SLACK_TEST_CHANNEL_ID,
      text: 'Hello!',
    });
    console.log(resultMessage);

    isSuccess = true;
  } catch (error) {
    console.error(error);
    isSuccess = false;
  }

  res.render('oauth', {
    isSuccess,
  });
});

module.exports = router;
```
### 環境変数の定義
Express.jsで使用するSlack OAuth用の環境変数を定義します。チャンネルIDはブラウザのURLから取得できます。
![スクリーンショット_2021-07-28_15_57_59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2221418/d22f0895-c6de-4feb-2377-475dfcba4e19.png)
#### app.env

```
...

# Slack Client ID
SLACK_CLIENT_ID=[App作成で生成したClient ID]
# Slack Client Secret
SLACK_CLIENT_SECRET=[App作成で生成したClient Secret]
# Slack メッセージのテスト送信に使用するChannel ID
SLACK_TEST_CHANNEL_ID=[AppをインストールしたチャンネルID]
```
## 動かしてみる
前回と同様に **docker-compose** コマンドで起動します

```
$ docker-compose up
```
下記のURLからOAuth認証フローを開始します。v1とはURLが異なるので注意してください。

```
https://slack.com/oauth/v2/authorize?client_id={client_id}&scope=chat:write&user_scope=
```
無事に認証画面が表示されました。「許可する」ボタンをクリックしてみましょう。
![スクリーンショット_2021-07-29_17_11_20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2221418/3cfbb0ca-1d3b-b29c-9f55-be05288befa5.png)
ブラウザに **Success!!** と表示されていればメッセージの送信まで成功しています。Slackの #general チャンネルを確認してみましょう。
![スクリーンショット_2021-07-29_17.17.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2221418/e78a4e3e-f00c-e23e-3d01-4eb89b261edd.png)
**#general** チャンネルにメッセージが送信されていることが確認できました。
![スクリーンショット_2021-07-28_15.44.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2221418/511b522e-f74f-980b-ac53-378f8bd63938.png)
## まとめ
Slack API v2 を使ったOAuth認証とメッセージの送信について書かれた記事がまだ少なかったので、Slack Appを作成する際にみなさまの参考になれば幸いです。