Skip to content

Commit

Permalink
Merge branch 'main' into issue-674
Browse files Browse the repository at this point in the history
  • Loading branch information
srajiang authored Feb 23, 2022
2 parents 213c64b + 113bbab commit 7e4f39d
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 48 deletions.
2 changes: 2 additions & 0 deletions .github/maintainers_guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ To build the docs locally, you must have [Ruby](https://www.ruby-lang.org/en/) i

To build the docs, navigate to the `docs` folder and run `bundle install` to install necessary gems (Ruby dependencies). Run `bundle exec jekyll serve` to start up a local server which will compile documentation source and serve its contents.

_(zsh users)_: If you are running into issues with permissions to install ruby gems during `bundle install`, you may need to add `eval "$(rbenv init - zsh)"` to your ~/.zshrc then run `source ~/.zshrc`.

#### Adding beta documentation
When documentation is in a beta state, it requires a new, distinct collection of docs. The process is a little nuanced, so make sure to build the documentation locally to make sure it appears how you expect. To create a new collection:
1. Add content
Expand Down
109 changes: 61 additions & 48 deletions docs/_basic/authenticating_oauth.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,55 @@ order: 15
---

<div class="section-content">
To make your Slack app ready for distribution, you will need to implement OAuth and store installation information (i.e. access tokens) securely. Bolt supports OAuth and will handle most of the work for you by setting up OAuth routes and verifying state.
To prepare your Slack app for distribution, you will need to enable Bolt OAuth and store installation information securely. Bolt supports OAuth and will handle the rest of the work; this includes setting up OAuth routes, state verification, and passing your app an installation object which you must store.

You will need to provide your:
* `clientId`, `clientSecret`, `stateSecret` and `scopes` (required)
* An `installationStore` option with `storeInstallation` and `fetchInstallation` handlers defined for storing installation data to a database *(optional, but highly recommended for production)*
To enable OAuth, you must provide:
* `clientId`, `clientSecret`, `stateSecret` and `scopes` _(required)_
* An `installationStore` option with handlers that store and fetch installations to your database *(optional, strongly recommended in production)*

---

##### Development and Testing

We've provided a default implementation of the `installationStore` `FileInstallationStore` which you can use during app development and testing.

```javascript
const { App } = require('@slack/bolt');
const { FileInstallationStore } = require('@slack/oauth');
const app = new App({
signingSecret: process.env.SLACK_SIGNING_SECRET,
clientId: process.env.SLACK_CLIENT_ID,
clientSecret: process.env.SLACK_CLIENT_SECRET,
stateSecret: 'my-state-secret',
scopes: ['channels:history', 'chat:write', 'commands'],
installationStore: new FileInstallationStore(),
});
```
:warning: This is **_not_** recommended for use in production - you should implement your own production store. Please see the example code to the right and [our other examples](https://github.com/slackapi/bolt-js/tree/main/examples/oauth).

---

##### Installing your App
Bolt for JavaScript provides an **Install Path** `/slack/install` out-of-the-box. This endpoint returns a simple `Add to Slack` button where users can initiate direct installs of your app with a valid `state` parameter. For example, if your app was hosted at `www.example.com`, you would be able to install your app at `www.example.com/slack/install`. If you would like to skip rendering the simple webpage and directly navigate end-users to Slack authorize URL, your app can set `installerOptions.directInstall: true` in the `App` constructor. See example code below:

* **Initiating an installation**: Bolt for JavaScript provides an **Install Path** `/slack/install` out-of-the-box. This endpoint returns a simple page with an `Add to Slack` button which initiates a direct install of your app (with a valid `state` parameter). An app hosted at _www.example.com_ would serve the install page at _www.example.com/slack/install_.
* 💡 You can skip rendering the provided default webpage and navigate users directly to Slack authorize URL by setting`installerOptions.directInstall: true` in the `App` constructor ([example](https://github.com/slackapi/bolt-js/blob/5b4d9ceb65e6bf5cf29dfa58268ea248e5466bfb/examples/oauth/app.js#L58-L64)).

* **Add to Slack**: The `Add to Slack` button initiates the OAuth process with Slack. After users have clicked Allow to grant your app permissions, Slack will call your app's **Redirect URI** (provided out-of-the-box), and prompt users to **Open Slack**. See the **Redirect URI** section below for customization options.

* **Open Slack**: After users **Open Slack**, and here after as your app processes events from Slack, your provided `installationStore`'s `fetchInstallation` and `storeInstallation` handlers will execute. See the **Installation Object** section below for more detail on arguments passed to those handlers.

* If you need additional authorizations (user tokens) from users inside a team when your app is already installed, or have a reason to dynamically generate an install URL, manually instantiate an `ExpressReceiver`, assign the instance to a variable named `receiver`, and then call `receiver.installer.generateInstallUrl()`. Read more about `generateInstallUrl()` in the [OAuth docs](https://slack.dev/node-slack-sdk/oauth#generating-an-installation-url).

* 💡 Bolt for JavaScript does not support OAuth for [custom receivers](#receiver). If you're implementing a custom receiver, you can use our [Slack OAuth library](https://slack.dev/node-slack-sdk/oauth#slack-oauth), which is what Bolt for JavaScript uses under the hood.


---
##### Redirect URI
Bolt for JavaScript provides a **Redirect URI Path** `/slack/oauth_redirect`. Slack uses the Redirect URI to redirect users after they complete an app's installation flow.

💡 You will need to add the full **Redirect URI** including your app domain in your Slack app configuration settings under **OAuth and Permissions**, e.g. `https://example.com/slack/oauth_redirect`.

To supply your own custom **Redirect URI**, you can set `redirectUri` in the App options and `installerOptions.redirectUriPath`. You must supply both, and the path must be consistent with the full URI.

```javascript
const app = new App({
Expand All @@ -24,20 +63,18 @@ const app = new App({
clientSecret: process.env.SLACK_CLIENT_SECRET,
stateSecret: 'my-state-secret',
scopes: ['chat:write'],
// optional code for directInstall. Defaults to false. When set to true, user does not see "Add to Slack" button page.
redirectUri: 'https://example.com/slack/redirect', // here
installerOptions: {
directInstall: true,
redirectUriPath: '/slack/redirect', // and here!
},
});
```

Once you click on the `Add to Slack` button, this will initiate the OAuth process. Users will see a green `Allow` button and dialogue of your app asking for permissions. Once you click on the `Allow` button, Slack will call your app's redirect URI. This will bring you to the `slack/oauth_redirect` endpoint and alert you in your browser to "Open Slack". After you **Open Slack** and here on after as your app processes events from Slack, `fetchInstallation` and `storeInstallation` handlers will execute.

Bolt provides a redirect URI out-of-the-box. See the following section, Redirect URI for more details.

Additionally, you can expect the `installation` object to look like the following:
---
##### Installation object
Bolt will pass your `installationStore`'s `storeInstallation` handler an `installation`. This can be a source of confusion for developers who aren't sure what shape of object to expect. The `installation` object should resemble:

```
```javascript
{
team: { id: 'T012345678', name: 'example-team-name' },
enterprise: undefined,
Expand All @@ -56,10 +93,9 @@ Additionally, you can expect the `installation` object to look like the followin
}
}
```
Bolt will pass your `fetchInstallation` and `deleteInstallation` handlers an `installQuery` object:

Similarly, the installQuery object will look like the following:

```
```javascript
{
userId: 'U012345678',
isEnterpriseInstall: false,
Expand All @@ -69,35 +105,9 @@ Similarly, the installQuery object will look like the following:
}
```

If you need additional authorizations (user tokens) from users inside a team when your app is already installed, or have a reason to dynamically generate an install URL, manually instantiate an `ExpressReceiver`, assign the instance to a variable named `receiver`, and then call `receiver.installer.generateInstallUrl()`. Read more about `generateInstallUrl()` in the [OAuth docs](https://slack.dev/node-slack-sdk/oauth#generating-an-installation-url).


💡 *Bolt for JavaScript does not support OAuth for [custom receivers](#receiver). If you're implementing a custom receiver, you can use our [Slack OAuth library](https://slack.dev/node-slack-sdk/oauth#slack-oauth), which is what Bolt for JavaScript uses under the hood.*


---
##### Redirect URI
Bolt for JavaScript provides a **Redirect URI Path** `/slack/oauth_redirect` out-of-the-box. Slack uses this to redirect users after they complete your app's installation flow.

💡 You will need to add the full **Redirect URI** including your app domain in your app configuration settings under **OAuth and Permissions**, e.g. `https://example.com/slack/oauth_redirect`.

If you'd like to supply your own custom **Redirect URI**, you can do this by setting `redirectUri` in the App options and `installerOptions.redirectUriPath`. You must supply both, and the path must be consistent with the full URI.

```javascript
const app = new App({
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'],
redirectUri: 'https://example.com/slack/redirect', // here
installerOptions: {
redirectUriPath: '/slack/redirect', // and here!
},
});
```
##### Org-wide installation
To add support for [org-wide installations](https://api.slack.com/enterprise/apps), you will need Bolt for JavaScript version `3.0.0` or newer. Make sure you have enabled org-wide installations in your app configuration settings under **Org Level Apps**.
To add support for [org-wide installations](https://api.slack.com/enterprise/apps), you will need Bolt for JavaScript version `3.0.0` or later. Make sure you have enabled org-wide installation in your app configuration settings under **Org Level Apps**.

Installing an [org-wide](https://api.slack.com/enterprise/apps) app from admin pages requires additional configuration to work with Bolt. In that scenario, the recommended `state` parameter is not supplied. Bolt will try to verify `state` and stop the installation from progressing.

Expand Down Expand Up @@ -129,9 +139,10 @@ const app = new App({
scopes: ['chat:write', 'commands'],
installationStore: {
storeInstallation: async (installation) => {
// change the lines below so they save to your database
// Bolt will pass your handler an installation object
// Change the lines below so they save to your database
if (installation.isEnterpriseInstall && installation.enterprise !== undefined) {
// support for org-wide app installation
// handle storing org-wide app installation
return await database.set(installation.enterprise.id, installation);
}
if (installation.team !== undefined) {
Expand All @@ -141,9 +152,10 @@ const app = new App({
throw new Error('Failed saving installation data to installationStore');
},
fetchInstallation: async (installQuery) => {
// change the lines below so they fetch from your database
// Bolt will pass your handler an installQuery object
// Change the lines below so they fetch from your database
if (installQuery.isEnterpriseInstall && installQuery.enterpriseId !== undefined) {
// org wide app installation lookup
// handle org wide app installation lookup
return await database.get(installQuery.enterpriseId);
}
if (installQuery.teamId !== undefined) {
Expand All @@ -153,7 +165,8 @@ const app = new App({
throw new Error('Failed fetching installation');
},
deleteInstallation: async (installQuery) => {
// change the lines below so they delete from your database
// Bolt will pass your handler an installQuery object
// Change the lines below so they delete from your database
if (installQuery.isEnterpriseInstall && installQuery.enterpriseId !== undefined) {
// org wide app installation deletion
return await database.delete(installQuery.enterpriseId);
Expand Down

0 comments on commit 7e4f39d

Please sign in to comment.