SlackのOAuth2を利用することになり、作業前は細かい動作がピンとこなかったので手順をまとめておきます。
Slackのユーザ情報を取得する実際のコードも載せています。
SlackのOAuth2.0については以下を参考にしました。
SlackでOAuth2を利用したときのメモ
Using OAuth 2.0 | Slack
手順概要
ざっくり以下の流れが必要になります。
- Slackアプリに登録する
 - Slackアプリの権限設定などを行う
 - 認可コードを受け取るコールバックサーバを立てる
 - Webブラウザで認可リクエスト投げる
 - コールバックサーバで認可コードを受け取り、そのコードを含めたリクエストを投げる
 
Slackアプリの登録
まず、Slackアプリを登録します
Slack API: Applications | Slack を開いて、Create New App を選択して、任意のアプリ名とチームを選択してください。
ClientIDの取得
Basic Informationのページの画面中央のApp CredentialsにIDが書いてあります
Client IDとClient Secretが必要になるので控えておいてください。(漏洩しないよう注意)
ただ、いつでも見えるので後でも良いです。
Recirect URLsの設定
左メニューより、OAuth & Permissionsを選択します。
Redirect URLsの項目からコールバックを受けるサーバのURLを追加します。
今回はローカルサーバに立てるので、http://localhost:3000を登録します。
Scopeの設定
画面下部のScopes中のSelect Permission Scopesからusers:readを選択します
認可のみであれば
identity.basicでも良いのですが、サンプルコードではユーザ情報まで取得しているため、これを選択します
ここまででSlack側の設定は完了です
OAuth認証を行うためにはコールバックを受け取るためのサーバが必要になります。
実際のアプリの場合はグローバルなサーバとなりますが、今回は確認なのでローカルホストにサーバを起動します。
サンプルコードは dbgso/slack-oauth2.0-client にあげています。
内容はコードの中身をみてください
コードの取得
git clone https://github.com/dbgso/slack-oauth2.0-client.git
cd slack-oauth2.0-client
yarn # or npm install
クライアントIDの設定
任意のエディタでapp.jsを編集して、SlackのクライアントIDを設定してください。
IDはClientの取得で控えておいたものです。
// Slack App の Client ID
- const slack_client_id = '';
+ const slack_client_id = '実際のclient_id';
// Slack App の Client Secret
- const slack_client_secret = ''
+ const slack_client_secret = '実際のclient_secret'
起動
node app.js
これでhttp://localhost:3000にSlackからのコールバックを受け取るサーバが立ち上がります。
Webブラウザから認可リクエスト
Webブラウザで以下のURLを開きます
SLACK_CLIENT_IDの部分は実際のclient_idに合わせてください。それ以外は変更なしで大丈夫です
https://slack.com/oauth/authorize?client_id=<SLACK_CLIENT_ID>&scope=identify&redirect_uri=http://localhost:3000/
以下のような画面が表示されるはずです。
ここでAuthorizeボタンを押すとredirect_uriで指定したhttp://localhost:3000に対してリクエストが送られます。
実行結果
Slackのユーザ情報を取得するまでの流れは以下のようになっています。
認可するのみであれば6.のユーザ情報取得までは必要ありません。
- Authorizedボタンを押下する
 - 
http://localhost:3000にHTTPリクエストが飛ぶ - HTTPリクエストのクエリ中に
認可コードが含まれているので取得 - 
認可コードを使ってhttps://slack.com/api/oauth.accessにリクエストしてアクセストークンを取得 - 
アクセストークンを使ってhttps://slack.com/api/auth.testにリクエストしてuser_idを取得 - 
user_idを使ってhttps://slack.com/api/users.infoにリクエストして、Slack上のユーザ情報を取得する 
うまく行けば以下のようなログがコンソール上に流れるはずです。
アクセストークン取得
https://slack.com/api/oauth.accessからのレスポンス
{ ok: true,
  access_token:
   '****-**********-************-************-********************************',
  scope: 'read,identify',
  user_id: '*********',
  team_name: '******',
  team_id: '*********' }
user_id取得
https://slack.com/api/auth.testからのレスポンス
{ ok: true,
  url: 'https://******.slack.com/',
  team: '******',
  user: '*****',
  team_id: '*********',
  user_id: '*********' }
Slackユーザ情報取得
https://slack.com/api/users.infoからのレスポンス
自身のSlackユーザ情報が表示されます。この情報は別にいらない、ということであればhttps://slack.com/api/users.infoへのリクエスト処理は不要です。
{
    "ok": true,
    "user": {
        "id": "**********",
        "team_id": "**********",
        "name": "**********",
        "deleted": false,
        "color": "d58247",
        "real_name": "**********",
        "tz": "Asia/Tokyo",
        "tz_label": "Japan Standard Time",
        "tz_offset": 32400,
        "profile": {
            "title": "",
            "phone": "",
            "skype": "",
            "real_name": "**********",
            "real_name_normalized": "**********",
            "display_name": "**********",
            "display_name_normalized": "**********",
            "status_text": "",
            "status_emoji": "",
            "status_expiration": 0,
            "avatar_hash": "**********",
            "image_original": "https://avatars.slack-edge.com/xxxx-xx-xx/****************_original.jpg",
            "email": "**********",
            "first_name": "***",
            "last_name": "***",
            "image_24": "https://avatars.slack-edge.com/xxxx-xx-xx/****************_24.jpg",
            "image_32": "https://avatars.slack-edge.com/xxxx-xx-xx/****************_32.jpg",
            "image_48": "https://avatars.slack-edge.com/xxxx-xx-xx/****************_48.jpg",
            "image_72": "https://avatars.slack-edge.com/xxxx-xx-xx/****************_72.jpg",
            "image_192": "https://avatars.slack-edge.com/xxxx-xx-xx/****************_192.jpg",
            "image_512": "https://avatars.slack-edge.com/xxxx-xx-xx/****************_512.jpg",
            "image_1024": "https://avatars.slack-edge.com/xxxx-xx-xx/****************_1024.jpg",
            "status_text_canonical": "",
            "team": "**********",
            "is_custom_image": true
        },
        "is_admin": false,
        "is_owner": false,
        "is_primary_owner": false,
        "is_restricted": false,
        "is_ultra_restricted": false,
        "is_bot": false,
        "is_app_user": false,
        "updated": 1557212637,
        "has_2fa": false
    }
}
失敗時ログ
こんなログが流れている場合は認可が失敗しています。
client_idが正しいか、Redirect URLsやPermissionsの設定を見直してみてください。
{ ok: false, error: 'invalid_code' }
{ ok: false, error: 'not_authed' }
認可のみであれば
identity.basicでも良いのですが、サンプルコードではユーザ情報まで取得しているため、これを選択します
ちなみに、こう書きましたが、identity.basicを選んだ状態で、ユーザ情報を取得しようとすると以下のようなエラーがでます。
{"ok":false,"error":"missing_scope","needed":"users:read","provided":"identify"}
コードの中身
- Node.js v10.15.3
 - express 4.17
 - request 2.88
 
でコールバックサーバを立てました。
リクエスト処理の度にネストが深くなってしまってみづらいですが、50行程度なので逆に小細工するよりこっちの方がみやすいかなと思ってます。
requestをPromiseにしてくれ...
と思ったらあるんですね。試しておきます
request-promiseを使ったHTTPクライアントを作る - Qiita
//@ts-check
const request = require('request')
const express = require('express');
const app = express();
// SSL関連でエラーが出るので、応急処置 SlackのAPIにリクエストするときに死んでいる模様。おそらく社内ネットワークのせい
process.env["NODE_TLS_REJECT_UNAUTHORIZED"] = "0";
// Slack App の Client ID
const slack_client_id = '';
// Slack App の Client Secret
const slack_client_secret = ''
app.get('/', (req, res) => {
    // 認可コードの取得
    const code = req.query["code"];
    // 認可コードを使って、アクセストークンをリクエストする
    request({
        url: "https://slack.com/api/oauth.access",
        method: "POST",
        form: {
            client_id: slack_client_id,
            client_secret: slack_client_secret,
            code: code,
            redirect_uri: "http://localhost:3000/"
        }
    }, (error, response, body) => {
        // レスポンスからアクセストークンを取得する
        const param = JSON.parse(body);
        console.log(param);
        const access_token = param['access_token']; // アクセストークン
        // ユーザIDを取得するためのリクエスト
        request("https://slack.com/api/auth.test",{
            method: "POST",
            form: {
                token: access_token
            }
        },(error, response, body) => {
            console.log(JSON.parse(body));
            // アクセストークンを使ってユーザ情報をリクエスト
            // 認可のみが目的の場合はここはなくても良い
            request("https://slack.com/api/users.info ", {
                method: 'POST',
                form: {
                    token: access_token,
                    user: param['user_id']
                }
            }, (error, response, body) => {
                res.send(JSON.parse(body));
            })
        })
    })
})
app.listen(3000, () =>{
        console.log('HTTP Server(3000) is running.');
});
おわりに
OAuth認証はほぼ初めてだったので、実際にコード書くと流れがわかってよかったです。
あと、認証と認可って言葉難しいですよね。使い方間違ってたら教えてください。。。
参考
AWS CognitoにGoogleとYahooとLINEアカウントを連携させる - Qiita
SlackでOAuthを利用して BOT投稿 するための アクセストークン を取得する方法 - UTALI
SlackでOAuth2を利用したときのメモ - Qiita
オウム返し slack bot をぱっとつくる - Qiita
Ignore invalid self-signed ssl certificate in node.js with https.request? - Stack Overflow
