Closed jp555soul closed 3 years ago
Hi @jp555soul! This definitely threw me at first: I've never seen a case where the token
and challenge
are both missing entirely.
I tried to reproduce your situation, beginning with a Socket Mode-enabled app and switching to HTTP. For the sake of ease, I used ngrok
as a tunnel, though the result should be the same if I were deploying to Heroku and a successful connection was made.
After switching out the Socket Mode-specific properties (appToken
, socketMode: true
) in the App
instantiation for non-Socket Mode ones (token
, signingSecret
), and restarting the server, all worked as expected and the verification succeeded.
Can you confirm on the Heroku end that the updated App
code with the non-Socket Mode credentials is what's currently being served from that new Request URL?
@misscoded Thanks for your response. I've gone ahead and updated the code (posted below) as well as pointed it to a new route to confirm an update, but I'm still getting the same results. Code and screenshot attached below.
require('dotenv').config();
const massive = require('massive')
const express = require('express')
const config = require('../config')
const { InstallProvider } = require('@slack/oauth');
const { App, ExpressReceiver, LogLevel } = require('@slack/bolt');
const uuid = require("uuid");
const packageJson = require('../package.json');
const app = express();
var http = require('http').Server(app);
//LOGGING
let agent = undefined;
const developerMode = true;
const logLevel = process.env.SLACK_LOG_LEVEL || LogLevel.DEBUG;
massive(config.database).then(async i => {
// Start your app
app.set('db', i);
console.log('Connected to DB');
http.listen(config.app.port, config.app.host, async () => {
console.log(`Server running on ${config.app.host}:${config.app.port}`)
});
}).catch(err => {
console.log("Unable to instantiate database, ", err);
});
const installer = new InstallProvider({
clientId: process.env.SLACK_CLIENT_ID,
clientSecret: process.env.SLACK_CLIENT_SECRET,
stateSecret: process.env.STATE_SECRET,
authVersion: 'v2',
//logLevel,
installationStore: {
storeInstallation: async (installation) => {
console.log('storeInstallation -- installer')
const db = app.get('db');
// change the line below so it saves to your database
if (installation.isEnterpriseInstall && installation.enterprise !== undefined) {
// support for org wide app installation
let entAccount = await db.table.findOne({ enterprise: installation.enterprise.id });
if (entAccount) {
const criteria = {
enterprise: installation.enterprise.id
}
let changes;
changes = {
'token': installation['bot']['token'],
'tokenraw': JSON.stringify(installation)
}
return await db.table.update(criteria, changes)
.then(success => {
console.log("The app was installed successfully. ENT");
}).catch(err => { console.log(err) });
} else {
return await db.table.insert({
enterprise: installation.enterprise.id,
token: installation['bot']['token'],
tokenraw: JSON.stringify(installation)
})
.then(success => {
console.log("The app was installed successfully. ENT");
}).catch(err => { console.log(err) });
}
}
if (installation.team !== undefined) {
// single team app installation
let teamAccount = await db.table.findOne({ team: installation.team.id });
if (teamAccount) {
const criteria = {
team: installation.team.id
}
let changes;
changes = {
'token': installation['bot']['token'],
'tokenraw': JSON.stringify(installation)
}
return await db.table.update(criteria, changes)
.then(success => {
console.log("The app was installed successfully. TEAM");
}).catch(err => { console.log(err) });
} else {
return await db.table.insert({
team: installation.team.id,
token: installation['bot']['token'],
tokenraw: JSON.stringify(installation)
})
.then(success => {
console.log("The app was installed successfully. TEAM");
}).catch(err => { console.log(err) });
}
}
throw new Error('Failed saving installation data to installationStore');
},
},
installerOptions: {
installPath: 'slack/install',
redirectUriPath: 'slack/oauth_redirect',
}
});
const bolt = 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,
//token: process.env.SLACK_APP_TOKEN,
//socketMode: true,
//agent,
//logLevel,
//developerMode,
stateVerification: false,
installationStore: {
storeInstallation: async (installation) => {
console.log('storeInstallation -- bolt')
//console.log(installation)
const db = app.get('db');
// change the line below so it saves to your database
if (installation.isEnterpriseInstall && installation.enterprise !== undefined) {
// support for org wide app installation
let entAccount = await db.table.findOne({ enterprise: installation.enterprise.id });
if (entAccount) {
const criteria = {
enterprise: installation.enterprise.id
}
let changes;
changes = {
'token': installation['bot']['token'],
'tokenraw': JSON.stringify(installation)
}
return await db.table.update(criteria, changes)
} else {
return await db.table.insert({
enterprise: installation.enterprise.id,
token: installation['bot']['token'],
tokenraw: JSON.stringify(installation)
});
}
}
if (installation.team !== undefined) {
// single team app installation
let teamAccount = await db.table.findOne({ team: installation.team.id });
if (teamAccount) {
const criteria = {
team: installation.team.id
}
let changes;
changes = {
'token': installation['bot']['token'],
'tokenraw': JSON.stringify(installation)
}
return await db.table.update(criteria, changes)
} else {
return await db.table.insert({
team: installation.team.id,
token: installation['bot']['token'],
tokenraw: JSON.stringify(installation)
})
.then(success => {
console.log("The app was installed successfully.");
}).catch(err => { console.log(err) });
}
}
throw new Error('Failed saving installation data to installationStore');
},
fetchInstallation: async (installQuery) => {
console.log('fetchInstallation - BOLT')
const db = app.get('db');
// change the line below so it fetches from your database
if (installQuery.isEnterpriseInstall && installQuery.enterpriseId !== undefined) {
// org wide app installation lookup
return await db.table.findOne({
enterprise: installQuery.enterpriseId
});
}
if (installQuery.teamId !== undefined) {
// single team app installation lookup
let data = await db.table.findOne({ team: installQuery.teamId });
let token = JSON.parse(data.tokenraw);
return token;
}
throw new Error('Failed fetching installation');
},
deleteInstallation: async (installQuery) => {
console.log('deleteInstallation - BOLT')
const db = app.get('db');
// change the line below so it deletes from your database
if (installQuery.isEnterpriseInstall && installQuery.enterpriseId !== undefined) {
// org wide app installation deletion
return await db.table.destroy({
enterprise: installQuery.enterpriseId
});
}
if (installQuery.teamId !== undefined) {
// single team app installation deletion
return await db.table.destroy({
team: installQuery.teamId
});
}
throw new Error('Failed to delete installation');
},
},
installerOptions: {
installPath: '/slack/install',
redirectUriPath: '/slack/oauth_redirect',
}
});
bolt.event('app_home_opened', async ({ event, client }) => {
try {
// Call views.publish with the built-in client
const result = await client.views.publish({
// Use the user ID associated with the event
user_id: event.user,
view: {
// Home tabs must be enabled in your app configuration page under "App Home"
"type": "home",
"blocks": [{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*Welcome <@" + event.user + "> :hand: :rocket:*"
}
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "New features coming soon."
}
}
]
}
});
} catch (error) {
console.error(error);
}
});
bolt.event("app_mention", async ({ logger, event, say }) => {
//logger.debug("app_mention event payload:\n\n" + JSON.stringify(event, null, 2) + "\n");
const result = await say({
text: `:wave: <@${event.user}> Hi there!`,
});
//logger.debug("say result:\n\n" + JSON.stringify(result, null, 2) + "\n");
});
app.get('/', async (req, res) => {
res.redirect('slack/install');
});
app.get('/slack/install', async (req, res, next) => {
try {
// feel free to modify the scopes
const genUrl = await installer.generateInstallUrl({
scopes: [
'channels:read',
'app_mentions:read',
'channels:history',
'channels:join',
'chat:write',
'commands',
'emoji:read',
'groups:history',
'im:history',
'incoming-webhook',
'mpim:history',
'reactions:write',
'conversations.connect:manage',
'chat:write.public',
'conversations.connect:read',
'conversations.connect:write',
'im:read',
'im:write',
'mpim:read',
'mpim:write',
],
})
res.send(`<a href=${genUrl}><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>`);
} catch (error) {
console.log(error)
}
});
app.get('/slack/oauth_redirect', (req, res) => {
installer.handleCallback(req, res);
});
app.post('/slack/events', (req, res) => {
console.log('SLACK EVENTS')
console.log(req.params)
console.log(req.body)
// if (req.body.type === 'url_verification') {
// res.send(req.body.challenge);
// }
res.send(bolt.receiver.endpoints[0]);
});
app.use('/slack/enable_events', (req, res) => {
console.log('SLACK ENABLE EVENTS')
console.log(req.params)
console.log(req.body)
// if (req.body.type === 'url_verification') {
// res.send(req.body.challenge);
// }
res.send(bolt.receiver.endpoints[0]);
});
(async () => {
await bolt.start(config.app.bolt);
console.log('⚡️ Bolt app is running!');
})();
Thanks for providing this code sample -- super helpful to be able to work from!
I ran your implementation locally (though commented out the DB-related items for testing purposes). The only thing I needed to change to get a successful verification was the port value being used for bolt.start(config.app.bolt)
. Since I have no visibility into what your value is, I replaced it to align with my own local implementation, which happened to be 3000
.
Our Heroku deployment guide links out to this documentation regarding selecting the correct port, which might be worth a glance if you haven't already seen it.
Can you verify that the port value assigned to config.app.bolt
matches what is expected on the Heroku side?
@misscoded Thanks for the assist. It ended up being a port issue with Heroku and I ended up moving to have the app completely in Bolt with it working.
Description
Moving bot from
socket mode
to HTTP events for release. When inputting my URL, the app shows that it iss not sending anychallenge
data. Nor am I seeing any in the request logs.What type of issue is this? (place an
x
in one of the[ ]
)Requirements (place an
x
in each of the[ ]
)Bug Report
Filling out the following details about bugs will help us solve your issue sooner.
Reproducible in:
package version:
^3.4.0
node version:
15.x
OS version(s):
OSX 11.5.1
Steps to reproduce:
Expected result:
POST response with data.
Actual result:
POST response with no data.
Attachments: