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