私はここ数日間、これを解決しようとしています。Slack/Bolt と組み込みの Express Server を使用して開発中の Slack アプリがあります。開発中は、インストール プロセスを正常に完了することができます。完了すると、ユーザーの資格情報 (認証トークン、チーム ID など) が返され、成功ページにリダイレクトされます。さらに、私のスラッシュ コマンドは期待どおりに機能します。
ただし、本番環境では、スラッシュ コマンドもインストール プロセスも機能しません。スラッシュ コマンドを実行すると、Slack に「dispatch_failed」エラーが返され、ログに次の検証エラーが返されます。
開発中のインストール プロセスは、必要なスコープを承認する Slack ページに移動する [slack に追加] ボタンのあるランディング ページから始まります。このフォームを送信すると、アプリが 503 エラーでタイムアウトになります。URL に「コード」が表示されていますが、処理されていません。別の認証方法を試すためにアプリをバラバラにする前に、どこが間違っているのか誰かが特定できることを期待していました。
重要なのは認証トークンです。開発中、アプリを宣言するときに xbot トークンを宣言します。本番用に削除し、イベント リスナー (スラッシュ コマンドなど) のコンテキスト変数からボット トークンを渡します。これは、ドキュメントからプロセスを理解した方法ですが、間違っている可能性があります...
const { App, ExpressReceiver } = require('@slack/bolt');
require('dotenv').config({ path: __dirname + '/.env' })
const axios = require('axios')
const request = require('request')
const bodyParser = require('body-parser')
const path = require('path')
const firebase = require("firebase");
//database config here (removed to de-clutter)
const fetchTeam = async (teamId) => {
try {
const ref = await database.ref('workspaces')
ref.orderByChild('team_id').equalTo(teamId).once('value', function (snapshot) {
return snapshot.val()
})
} catch (e) {
console.log(e);
}
}
// Create a Bolt Receiver
const receiver = new ExpressReceiver({ signingSecret: process.env.SLACK_SIGNING_SECRET });
const app = new App({
signingSecret: process.env.SLACK_SIGNING_SECRET,
clientId: process.env.SLACK_CLIENT_ID,
clientSecret: process.env.SLACK_CLIENT_SECRET,
stateSecret: process.env.STATE_SECRET,
scopes: ['chat:write', 'chat:write:bot', 'im:write', 'commands', 'incoming-webhook', 'users:read', 'users:read.email'],
// scopes: ['chat:write', 'chat:write:bot', 'channels:history', 'groups:history', 'im:history', 'commands', 'incoming-webhook', 'users:read', 'users:read.email'],
installationStore: {
storeInstallation: async (installation) => {
return await database.ref('workspaces').push({ team_id: installation.team.id, installation })
},
fetchInstallation: async (InstallQuery) => {
return await fetchTeam(InstallationQuery.teamId)
},
},
//removed token for production
//token: process.env.SLACK_BOT_TOKEN,
receiver
});
//a bunch of stuff my slack app does here (removed)
receiver.router.get('/slack/oauth_redirect', async (req, res) => {
var options = {
uri: 'https://slack.com/api/oauth.v2.access?code='
+ req.query.code +
'&client_id=' + process.env.SLACK_CLIENT_ID +
'&client_secret=' + process.env.SLACK_CLIENT_SECRET,
method: 'GET'
}
request(options, async (error, response, body) => {
var JSONresponse = JSON.parse(body)
if (!JSONresponse.ok) {
res.status(500).send("Error: ", JSONresponse)
} else {
const newOBJ = {
team_id: JSONresponse.team.id,
...JSONresponse
}
console.log(newOBJ);
await database.ref('workspaces').push(newOBJ)
}
})
})
receiver.router.post('/', (req, res) => {
const payload = JSON.parse(req.body.payload)
res.send(req.data);
});
receiver.router.post('/slack/events', (req, res) => {
res.send(req.data);
});
receiver.router.post('/actions', (req, res) => {
res.send(req.data);
});
// Listen for a slash command invocation
app.command('/commandName', async ({ command, ack, say, context }) => {
await ack();
try {
// Call the users.info method using the built-in WebClient
const result = await app.client.users.info({
token: context.botToken,
//in development i use the code below
// token: process.env.SLACK_BOT_TOKEN,
user: user
});
}
catch (error) {
console.error(error);
}
await say({
"blocks": [
{
"type": "section",
"text": {
"type": "plain_text",
"text": `Hi there ,! Here are some ways you can use Slack to get things done with Webstacks:`,
"emoji": true
}
},
{
"type": "actions",
"elements": [
{
"type": "button",
"text": {
"type": "plain_text",
"text": "Raise a Request"
},
"value": "create_request",
"action_id": "create_request"
},
{
"type": "button",
"text": {
"type": "plain_text",
"text": "Leave a Review",
},
"url": "https://kittycats.com"
}
]
}
]
})
});
(async () => {
// Start your app
await app.start(process.env.PORT || 3000);
console.log('⚡️ Bolt app is running!');
})();