サンプルコードの元: https://github.com/sisisin-sandbox/try-socket-mode/blob/master/src/index.ts
Expressを使ってSlackのOAuthフローをしつつSocket Modeを利用する
boltでSocketModeReceiverを使ってOAuthフローを実装するまでは出来るが、そこにユーザー定義のエンドポイントを足す事ができない(SocketModeReceiverとExpressReceiverを同時に使えない)ため、もしそのようなことがしたい場合は @slack/oauth
と @slack/socket-mode
パッケージを使って実装する必要がある
サンプル実装
import { InstallProvider } from '@slack/oauth';
import { SocketModeClient } from '@slack/socket-mode';
import express from 'express';
import fs from 'fs';
import https from 'https';
const app = express();
const server = https.createServer(
{ key: fs.readFileSync(process.env.PRIV_KEY!, 'utf-8'), cert: fs.readFileSync(process.env.CERT!, 'utf-8') },
app,
);
const socketClient = new SocketModeClient({ appToken: process.env.SLACK_APP_TOKEN! });
const installer = new InstallProvider({
clientId: process.env.CLIENT_ID!,
clientSecret: process.env.CLIENT_SECRET!,
stateSecret: 'my-state-secret',
});
app.get('/slack/install', async (req, res, next) => {
const url = await installer.generateInstallUrl({
scopes: [],
userScopes: ['channels:read', 'channels:history', 'im:history'],
});
res.send(
`<a href=${url}><img alt=""Add to Slack"" height="40" width="139" src="https://platform.slack-edge.com/img/add_to_slack.png" srcset="https://platform.slack-edge.com/img/add_to_slack.png 1x, https://platform.slack-edge.com/img/add_to_slack@2x.png 2x" /></a>`,
);
});
app.get('/slack/oauth_redirect', async (req, res) => {
await installer.handleCallback(req, res, {
success: (installation, options, callbackReq, callbackRes) => {
if ((callbackReq as any).session) {
(callbackReq as any).session.slack = installation;
}
(callbackRes as any).redirect('/');
},
});
});
app.get('/', (req, res) => {
res.send('ok');
});
socketClient.on('message', (event) => {
event.ack();
console.log(event.event.text);
});
async function main() {
server.listen(process.env.PORT || 3000, () => {
console.log(`server running`);
});
await socketClient.start();
}
main().catch((err) => console.error(err));
基本的に @slack/oauth と @slack/socket-mode のドキュメントに従えばいいです
(ちなみにこれらのドキュメントにたどり着くのが難しいのでnpmから辿ると探しやすいです。厳しい。)
expressを使う場合、セッションをexpress-sessionなどを使ってexpress側に持たせる事が多いと思う
その場合、ユーザーごとの installation
情報はサンプル実装の installer.handleCallback()
呼び出しの部分にあるように、sessionに持たせる形になる
セッションでSlackのtokenをもたせるので、ドキュメントにあるような InstallProvider
で installationStore
を実装する必要はない(warnが出るので若干気持ち悪いが
oauthで認可を得たユーザーの権限でevent apiのイベントを受け取る方法
上記サンプルコード内の↓の部分のように、 userScope
にて権限を設定すると出来る
至極基本的なことのはずなのにドキュメントの記載が見つけられなくてこれを発見するのに大変苦労した・・・
(見つけたのは確かpythonのサンプルコードでuserScopeを指定してる場所があっておや、と思ったとかだった。リンク失念)
const url = await installer.generateInstallUrl({
scopes: [],
userScopes: ['channels:read', 'channels:history', 'im:history'],
});
apps.event.authorizations.listを素直に叩くとinvalid_authが出る
botでは受け取れないユーザー固有のイベント(DMの受信など)を受け取るようなアプリを書く場合、EventAPIによって飛んできたEventが「どのユーザーに見せるべきか」を判断するために apps.event.authorizations.listを叩く必要がある
さて@slack/boltや@slack/web-apiを普通に使って以下のように取得しようとすると invalid_auth
になってしまう
app.event('message', async({client,body, event})=>{
await client.apps.event.authorizations.list({...})
})
const webClient = new WebClient(token)
webClient.apps.event.authorizations.list({...})
とりあえずこのissueコメントのとおりにやれば動くのでそのようにすると動く
これハマるとエラーメッセージがinvalid_authしか返ってこないのでしんどい
以上雑多な感じにメモしました
slackのドキュメント、充実してる気がするんだけど欲しい情報に辿り着きにくかったり、エラーが出たりしたときにどうすれば対処できるのかが分かりにくかったりで凝ったことやろうとすると結構しんどい・・・