Skip to content

Commit

Permalink
Fix slackapi#977 Add a way to turn off web page rendering for "/slack…
Browse files Browse the repository at this point in the history
…/install"
  • Loading branch information
seratch committed Aug 25, 2021
1 parent 02d601d commit 657b94b
Show file tree
Hide file tree
Showing 11 changed files with 488 additions and 12 deletions.
3 changes: 3 additions & 0 deletions examples/oauth/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# node / npm
node_modules/
package-lock.json
55 changes: 55 additions & 0 deletions examples/oauth/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Bolt for JavaScript OAuth Test App

This is a quick example app to test [OAuth](https://api.slack.com/authentication/oauth-v2) with Bolt for JavaScript.

If using OAuth, Slack requires a public URL where it can send requests. In this guide, we'll be using [`ngrok`](https://ngrok.com/download). Checkout [this guide](https://api.slack.com/tutorials/tunneling-with-ngrok) for setting it up. OAuth installation is only needed for public distribution. For internal apps, we recommend installing via your app configuration.

Before we get started, make sure you have a development workspace where you have permissions to install apps. If you don’t have one setup, go ahead and [create one](https://slack.com/create). You also need to [create a new app](https://api.slack.com/apps?new_app=1) if you haven’t already. You will need to enable Socket Mode and generate an App Level Token.

## Install Dependencies

```
npm install
```

## Setup Environment Variables

This app requires you setup a few environment variables. You can find these values in your [app configuration](https://api.slack.com/apps).

```bash
export CLIENT_ID=YOUR_SLACK_CLIENT_ID
export CLIENT_SECRET=YOUR_SLACK_CLIENT_SECRET
export SIGNING_SECRET=YOUR_SLACK_SIGNING_SECRET
```

## Run the App

Start the app with the following command:

```
npm start
```

### Running with OAuth

Only implement OAuth if you plan to distribute your application across multiple workspaces. Uncomment out the OAuth specific comments in the code. If you are on dev instance, you will have to uncomment out those options as well.

Start `ngrok` so we can access the app on an external network and create a redirect URL for OAuth.

```
ngrok http 3000
```

This output should include a forwarding address for `http` and `https` (we'll use the `https` one). It should look something like the following:

```
Forwarding https://3cb89939.ngrok.io -> http://localhost:3000
```

Then navigate to **OAuth & Permissions** in your app configuration and click **Add a Redirect URL**. The redirect URL should be set to your `ngrok` forwarding address with the `slack/oauth_redirect` path appended. ex:

```
https://3cb89939.ngrok.io/slack/oauth_redirect
```

Start the OAuth flow from https://{your own subdomain}.ngrok.io/slack/install
68 changes: 68 additions & 0 deletions examples/oauth/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
const { App, LogLevel } = require('@slack/bolt');

const databaseData = {};
const database = {
set: async (key, data) => {
databaseData[key] = data
},
get: async (key) => {
return databaseData[key];
},
};

const app = new App({
logLevel: LogLevel.DEBUG,
signingSecret: process.env.SLACK_SIGNING_SECRET,
clientId: process.env.SLACK_CLIENT_ID,
clientSecret: process.env.SLACK_CLIENT_SECRET,
stateSecret: 'my-state-secret',
scopes: ['chat:write'],
installationStore: {
storeInstallation: async (installation) => {
// change the line below so it saves to your database
if (installation.isEnterpriseInstall && installation.enterprise !== undefined) {
// support for org wide app installation
return await database.set(installation.enterprise.id, installation);
}
if (installation.team !== undefined) {
// single team app installation
return await database.set(installation.team.id, installation);
}
throw new Error('Failed saving installation data to installationStore');
},
fetchInstallation: async (installQuery) => {
// change the line below so it fetches from your database
if (installQuery.isEnterpriseInstall && installQuery.enterpriseId !== undefined) {
// org wide app installation lookup
return await database.get(installQuery.enterpriseId);
}
if (installQuery.teamId !== undefined) {
// single team app installation lookup
return await database.get(installQuery.teamId);
}
throw new Error('Failed fetching installation');
},
deleteInstallation: async (installQuery) => {
// change the line below so it deletes from your database
if (installQuery.isEnterpriseInstall && installQuery.enterpriseId !== undefined) {
// org wide app installation deletion
return await database.delete(installQuery.enterpriseId);
}
if (installQuery.teamId !== undefined) {
// single team app installation deletion
return await database.delete(installQuery.teamId);
}
throw new Error('Failed to delete installation');
},
},
installerOptions: {
// If this is true, /slack/install redirects installers to the Slack authorize URL
// without rendering the web page with "Add to Slack" button.
directInstallUrlEnabled: true,
}
});

(async () => {
await app.start(process.env.PORT || 3000);
console.log('⚡️ Bolt app started');
})();
11 changes: 11 additions & 0 deletions examples/oauth/link.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#!/bin/bash

current_dir=`dirname $0`
cd ${current_dir}
npm unlink @slack/bolt \
&& npm i \
&& cd ../.. \
&& npm link \
&& cd - \
&& npm i \
&& npm link @slack/bolt
5 changes: 5 additions & 0 deletions examples/oauth/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 13 additions & 0 deletions examples/oauth/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"name": "bolt-oauth-example",
"version": "1.0.0",
"description": "Example app using OAuth",
"main": "app.js",
"scripts": {
"start": "node app.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Slack Technologies, Inc.",
"license": "MIT",
"dependencies": {}
}
11 changes: 10 additions & 1 deletion src/receivers/ExpressReceiver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ interface InstallerOptions {
authVersion?: InstallProviderOptions['authVersion']; // default 'v2'
metadata?: InstallURLOptions['metadata'];
installPath?: string;
directInstallUrlEnabled?: boolean; // see https://api.slack.com/start/distributing/directory#direct_install
redirectUriPath?: string;
callbackOptions?: CallbackOptions;
userScopes?: InstallURLOptions['userScopes'];
Expand Down Expand Up @@ -139,7 +140,15 @@ export default class ExpressReceiver implements Receiver {
scopes: scopes!,
userScopes: installerOptions.userScopes,
});
res.send(renderHtmlForInstallPath(url));
if (installerOptions.directInstallUrlEnabled) {
// If a Slack app sets "Direct Install URL" in the Slack app configruation,
// the installation flow of the app should start with the Slack authorize URL.
// See https://api.slack.com/start/distributing/directory#direct_install for more details.
res.redirect(url);
} else {
// The installation starts from a landing page served by this app.
res.send(renderHtmlForInstallPath(url));
}
} catch (error) {
next(error);
}
Expand Down
Loading

0 comments on commit 657b94b

Please sign in to comment.