You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Apologies in advance if this isn't the right place to ask, but I didn't know where else to turn to after a lot of Googling and ChatGPT/Perplexity.
I am trying to setup OAuth for my BoltJS app so that I can prepare my app for distribution on multiple workspaces. I'm not very familiar building with OAuth so the inner workings are not familiar to me. So far, I'm following along the BoltJS documentation, which has been quite easy to follow for the most part. But where the BoltJS documentation says once OAuth is enabled, I should see an automatically rendered App Install page located at the URL path /slack/install, my server is instead giving me a 404 error and that this path is unhandled.
I don't understand what the issue could be because so far my app is very simple: it has only implemented
A single slash command that opens a single modal view state app.command
The corresponding view submission event app.view
A message listener (app.message)
Thank you in advance for your help! My app.js is appended below.
Reproducible in:
The Slack SDK version
"slack/bolt": "^3.17.1"
Node.js runtime version
v20.11.1
OS info
ProductName: macOS
ProductVersion: 14.1.2
BuildVersion: 23B92
Darwin Kernel Version 23.1.0: Mon Oct 9 21:28:45 PDT 2023; root:xnu-10002.41.9~6/RELEASE_ARM64_T6020
Steps to reproduce:
(Share the commands to run, source code, and project settings)
Start my app using node app.js
Hit the URL path of the Slack Install page that is supposed to be rendered automatically by Bolt (http://my-domain.ngrok-free.app/slack/install)
My app is working fine when events and user interactions (with modals, multi-select menus built in Block Kit, etc.) are sending requests to http://my-domain.ngrok-free.app/slack/events. So it's not an issue with my ngrok tunnel or the app itself.
Actual result:
After entering http://my-domain.ngrok-free.app/slack/install in my browser:
I see in my terminal log the following error message:
[INFO] Unhandled HTTP request (GET) made to /slack/install
And in the ngrok command line (the 404 Not Found for /slack/install):
HTTP Requests
-------------
POST /slack/events 200 OK
POST /slack/events 200 OK
GET /slack/install 404 Not Found
GET /slack/install 404 Not Found
POST /slack/events 200 OK
POST /slack/events 200 OK
My app.js
const { App } = require('@slack/bolt');
const { FileInstallationStore} = require ('@slack/oauth')
const app = new App({
token: process.env.SLACK_BOT_TOKEN,
signingSecret: process.env.SLACK_SIGNING_SECRET,
clientId: process.env.SLACK_CLIENT_ID,
clientSecret: process.env.SLACK_CLIENT_SECRET,
stateSecret: 'my-secret', //Note: This should be randomly generated and stored/rotated as an environment variable in production
scopes: ['chat:write', 'commands'],
installationStore: new FileInstallationStore()
});
//Retrieve the names of conversations or users given their Slack conversation IDs
async function getNames(client, ids) {
const names = [];
for (const id of ids) {
try {
if (id.startsWith('U')) {
// Handle user IDs
const result = await client.users.info({ user: id });
if (result.ok) {
names.push(result.user.real_name); // or `result.user.name` for the username
} else {
names.push(`Failed to fetch details for user ID: ${id}`);
}
} else {
// Handle conversation IDs
const result = await client.conversations.info({ channel: id });
if (result.ok) {
names.push(result.channel.name);
} else {
names.push(`Failed to fetch details for conversation ID: ${id}`);
}
}
} catch (error) {
console.error(`Error fetching details for ID: ${id}`, error);
names.push(`Error for ID: ${id}`);
}
}
return names;
}
//Open a Modal window for the command /alertbot-create
app.command('/alertbot-create', async ({ ack, body, client }) => {
// Acknowledge the command request
await ack();
console.log("command invoked: alertbot-create");
try {
// Call views.open with the built-in client
const result = await client.views.open({
// Pass a valid trigger_id within 3 seconds of receiving the command
trigger_id: body.trigger_id,
// View payload
view: {
"type": "modal",
"callback_id": "alertbot_create_view",
"title": {
"type": "plain_text",
"text": "Create a new Alert"
},
"submit": {
"type": "plain_text",
"text": "Submit"
},
"blocks": [
{
"type": "input",
"block_id": "search_phrase_block",
"element": {
"type": "plain_text_input",
"action_id": "search_phrase_action",
"multiline": false,
"placeholder": {
"type": "plain_text",
"text": "The exact word or phrase that you want to listen out for"
}
},
"label": {
"type": "plain_text",
"text": "Search Phrase"
}
},
{
"type": "input",
"block_id": "alert_message_contents_block",
"element": {
"type": "plain_text_input",
"multiline": true,
"action_id": "alert_message_contents_action",
"placeholder": {
"type": "plain_text",
"text": "The contents of your alert message, excluding users or groups"
}
},
"label": {
"type": "plain_text",
"text": "Alert Message Contents",
"emoji": true
}
},
{
"type": "input",
"block_id": "recipients_block",
"element": {
"type": "multi_conversations_select",
"placeholder": {
"type": "plain_text",
"text": "Select conversations"
},
"filter": {
"include": [
"public",
"private",
"im"
],
"exclude_bot_users": true
},
"action_id": "recipients_action",
"default_to_current_conversation": true
},
"label": {
"type": "plain_text",
"text": "Select users to @mention and/or #channels to post to"
}
},
{
"type": "input",
"block_id": "alert_configuration_block",
"element": {
"type": "checkboxes",
"options": [
{
"text": {
"type": "plain_text",
"text": "Send alert as DM only"
},
"description": {
"type": "mrkdwn",
"text": "Alerts will be sent from AlertBot directly to users mentioned. Channels will be ignored."
},
"value": "is_dm_only"
},
{
"text": {
"type": "plain_text",
"text": "Disable threaded alerts"
},
"description": {
"type": "mrkdwn",
"text": "For alerts posted as a response to the trigger message in its original channel, do not reply in a thread."
},
"value": "disable_threading"
},
{
"text": {
"type": "plain_text",
"text": "Disable link to trigger message"
},
"description": {
"type": "mrkdwn",
"text": "For alerts posted elsewhere besides the original channel, do not include a link to the triggering message."
},
"value": "disable_link_to_trigger"
}
],
"action_id": "alert_configuration_action"
},
"label": {
"type": "plain_text",
"text": "Alert configuration",
"emoji": true
}
}
]
}
});
} catch (error) {
console.error(error);
}
});
//Listen to user selection of @users or #channels in the multi conversations select menu of the alertbot-create modal
app.action('multi_conversations_select-action', async({ack, body, client}) => {
await ack();
console.log("action captured: multi_conversations_select-action");
});
//Listen to the Modal window submission for /alertbot-create
app.view('alertbot_create_view', async ({ ack, body, view, client}) => {
console.log("view submitted: alertbot_create_view");
// Check if at least one conversation is selected in the recipients_action multi conversations select menu
const selectedConversations = view.state.values.recipients_block.recipients_action.selected_conversations;
if (!selectedConversations || selectedConversations.length === 0) {
// Acknowledge the view submission with an error if no conversations are selected
return await ack({
response_action: 'errors',
errors: {
recipients_action: 'Please select at least one conversation.'
}
});
}
// Acknowledge the view submission event
await ack();
const user_id = body.user.id;
const alert_search_phrase = view.state.values.search_phrase_block.search_phrase_action.value;
const alert_message_contents = view.state.values.alert_message_contents_block.alert_message_contents_action.value;
const selected_config_options = view.state.values.alert_configuration_block.alert_configuration_action.selected_options;
try {
//Retrieve conversation names from conversation IDs
const names = await getNames(client, selectedConversations);
console.log("Conversation names:", names);
//Extract alert configuration options
const configOptions = selected_config_options.map(option => option.value);
console.log(configOptions);
await client.chat.postMessage({
channel: user_id,
text: "You created a new AlertBot alert",
blocks: [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "⚠️ *You created a new alert*"
}
},
{
"type": "section",
"fields": [
{
"type": "mrkdwn",
"text": "*Search Phrase*"
},
{
"type": "plain_text",
"text": alert_search_phrase
},
{
"type": "mrkdwn",
"text": "*Alert Message Contents*"
},
{
"type": "plain_text",
"text": alert_message_contents
},
{
"type": "mrkdwn",
"text": "*Recipients*"
},
{
"type": "plain_text",
"text": names.join(", ")
},
{
"type": "mrkdwn",
"text": "*Configuration Options*"
},
{
"type": "plain_text",
"text": configOptions.join(", ")
}
]
}
]
});
} catch (error) {
console.error(error);
}
});
// Listen for messages containing "ping" and respond
app.message('ping', async ({ message, say }) => {
console.log("messge event: specific string");
try {
await say({
text: `Hello <@${message.user}>!`,
blocks: [
{
type: "section",
text: {
type: "mrkdwn",
text: `Hey <@${message.user}>, check this out!`
},
accessory: {
type: "button",
text: {
type: "plain_text",
text: "Click me!"
},
url: "https://example.com"
}
}
]
});
} catch (error) {
console.error(error);
}
});
(async () => {
let port = process.env.PORT;
if (port == null || port == "") {
port = 8000;
}
// app.listen(port);
await app.start(process.env.PORT || 3000);
console.log('Slack app is running on port ' + (process.env.PORT || 3000));
})();
The text was updated successfully, but these errors were encountered:
Hi @zhifengkoh, thanks for asking the question. I just quickly checked if your example app works for me, and I didn't see any issues with it (token: process.env.SLACK_BOT_TOKEN, is unnecessary though). http://localhost:300/slack/install services the page as I expect. I guess your ngrok might be forwarding your browser request to a different process or your changes to enable the OAuth flow might not be reflected to the running process. I hope you will figure the cause out soon.
👋 It looks like this issue has been open for 30 days with no activity. We'll mark this as stale for now, and wait 10 days for an update or for further comment before closing this issue out. If you think this issue needs to be prioritized, please comment to get the thread going again! Maintainers also review issues marked as stale on a regular basis and comment or adjust status if the issue needs to be reprioritized.
Apologies in advance if this isn't the right place to ask, but I didn't know where else to turn to after a lot of Googling and ChatGPT/Perplexity.
I am trying to setup OAuth for my BoltJS app so that I can prepare my app for distribution on multiple workspaces. I'm not very familiar building with OAuth so the inner workings are not familiar to me. So far, I'm following along the BoltJS documentation, which has been quite easy to follow for the most part. But where the BoltJS documentation says once OAuth is enabled, I should see an automatically rendered App Install page located at the URL path
/slack/install
, my server is instead giving me a 404 error and that this path is unhandled.I don't understand what the issue could be because so far my app is very simple: it has only implemented
app.command
app.view
app.message
)Thank you in advance for your help! My app.js is appended below.
Reproducible in:
The Slack SDK version
"slack/bolt": "^3.17.1"
Node.js runtime version
v20.11.1
OS info
Steps to reproduce:
(Share the commands to run, source code, and project settings)
node app.js
http://my-domain.ngrok-free.app/slack/install
)Expected result:
I was expecting to see the default slack install webpage rendered by Bolt, as mentioned here: https://slack.dev/bolt-js/concepts#authenticating-oauth.
My app is working fine when events and user interactions (with modals, multi-select menus built in Block Kit, etc.) are sending requests to
http://my-domain.ngrok-free.app/slack/events
. So it's not an issue with my ngrok tunnel or the app itself.Actual result:
After entering
http://my-domain.ngrok-free.app/slack/install
in my browser:/slack/install
):My app.js
The text was updated successfully, but these errors were encountered: