Installing with OAuth

Slack apps are installed with a v2 OAuth 2.0 flow. We're sorry about all the "2s": OAuth 2.0 refers to the 2.0 version of the OAuth spec, and this is our second version of OAuth 2.0. For the rest of this guide, we'll just refer to it as "OAuth".

For posterity, this OAuth flow works the same as the OAuth flow for legacy Slack apps. Only a few details have changed; URL and method names have gained a v2, and the shape of the OAuth access response now puts bot access tokens first. We created a version 2 of the OAuth flow because it provides more granular Slack scopes, especially for bot users. Your app can act with its own identity, instead of acting on behalf of users β€” all without requesting excessive permissions that could cause installations to be rejected.

How it works: a high-level overview

OAuth allows a user in any Slack workspace to install your app. At the end of the OAuth flow, your app gains an access token. Your app's access token opens the door to Slack API methods, events, and other features. During the OAuth flow, you specify which scopes your app needs. Those scopes determine exactly which doors your app can open.

Implementing an OAuth flow can feel hard because there are a lot of steps, but your app really only has to worry about three steps to make OAuth work: requesting scopes, waiting for a user to give their approval, and exchanging a temporary authorization code for an access token. Redirecting a user to Slack can be done with a single link. For example:

<a href="">Add to Slack</a>

Replace the scope= with the scopes you'd like and the client_id with your app's client ID, and you've already got the redirect down. You can even turn that link into an Add to Slack button by using the generator below:

Looks like you don't have any apps yet.

Create an App

Obtaining access tokens with OAuth

Your app obtains an access token in three steps:

  1. Requesting scopes.
  2. Waiting for a user to approve your requested scopes.
  3. Exchanging a temporary authorization code for an access token.

Why is there a third exchanging step in OAuth at all? Why doesn't Slack send your app an access token directly after the user okays your app? The reason is two-factor authentication. You have to prove both that you have the right temporary authorization code, and that you have your app's client secret.

Requesting scopes

While developing your app, you'll determine a minimum list of scopes that your app requires to work. When a user installs your app in their workspace, you'll request those scopes.

To request scopes, redirect Slack users to If you're developing a GovSlack app for use by public sector customers, redirect users to

A scope conflict occurs when attempting to combine Sign in with Slack (SIWS) user scopes with non-Sign in with Slack scopes in the same OAuth flow. Each set of scopes must be requested in a separate OAuth flow.

Include both your app's client ID, which is found in the App Management page, and a comma-separated list of scopes, such as: scope=incoming-webhook,commands. The full redirect URL will look something like this:,commands&client_id=3336676.569200954261

The scope list requests scopes for your app's bot user. If you have specific need for a user token (for example, so that you can act on behalf of a user), provide a user_scope parameter with requested user scopes instead of, or in addition to, the scope parameter.

Also note that each installation can result in additive scopes. For example, if a user installs your app in a workspace where you request channels:history and then installs your app again where you request channels:read, both channels:history and channels:read will be assigned to the token. There is no way to remove scopes from an existing token without revoking it entirely.

When requesting scopes, you also need to tell Slack where to send your temporary authorization code afterward. Include a redirect_uri parameter in the URL above. The redirect_uri is where Slack will send the user back to, along with the temporary authorization code, once the user okays your app. The redirect_uri must use HTTPS. Alternatively, you can configure a Redirect URL in the App Management page under OAuth & Permissions. A Redirect URL must also use HTTPS.

When there are multiple Redirect URL values configured, the redirect_url parameter must be sent in both the Authorize and Access steps described below, and the parameter value must be the same for both steps β€” otherwise, you will encounter a bad_redirect_uri error:

  1. Authorize: You direct the user to the corresponding /oauth/v2/authorize path (this can be done with a link or button, for example). Send the redirect_uri in this step.
  2. Redirect: Slack redirects the user to what was specified as the redirect_uri in the previous step, and adds a verification code to that URL.
  3. Access: Your server retrieves the verification code from the previous step and sends it to the oauth.v2.access API endpoint to exchange that code for an access token.Β Β If you sent a redirect_uri field in the first step, you must send that same field with the same value in this step.

If there are multiple Redirect URL values configured, but no redirect_uri parameter is sent, the OAuth flow will use the first Redirect URL listed on the App Management page. You can use the redirect_uri parameter in your oauth/v2/authorize redirect as mentioned above and configure a Redirect URL in the App Management page. Your redirect_uri must match or be a subdirectory of a Redirect URL configured under App Management. A Redirect URL can not contain an anchor (#).


GOOD redirect_uri:

The team parameter

When a valid team ID is passed to team and the authenticating user is already signed in to that workspace, passing this parameter ensures the user will auth against that workspace.

If the user is not signed in yet, the user will be asked to specify a workspace to sign in to. That workspace will then be used as they complete the authorization flow, regardless of any team parameter you provided when the flow began.

If you omit the optional team parameter, the user will be allowed to choose which workspace they are authenticating against.

Waiting for a user to approve your requested scopes

Good news! Your app doesn't really have to do anything.

Prepare for the return of a user by listening for HTTP requests at whatever Redirect URL you specified.

Exchanging a temporary authorization code for an access token

If all goes well, a user goes through the Slack app installation and okays your app with all the scopes it requests. Then, Slack redirects the user back to your specified Redirect URL.

Parse the HTTP request that lands at your Redirect URL for a code field. That's your temporary authorization code, which expires after ten minutes. Check the state parameter if you sent one along with your initial user redirect. If it doesn't match what you sent, consider the authorization a forgery.

Now, you just need to exchange the code for an access token. You'll do this by calling the oauth.v2.access method as follows:

curl -F code=1234 -F client_id=3336676.569200954261 -F client_secret=ABCDEFGH

Once you complete your access call, Slack sends you an HTTP request response containing an access token. It looks something like this:

    "ok": true,
    "access_token": "xoxb-17653672481-19874698323-pdFZKVeTuE8sk7oOcBrzbqgy",
    "token_type": "bot",
    "scope": "commands,incoming-webhook",
    "bot_user_id": "U0KRQLJ9H",
    "app_id": "A0KRD7HC3",
    "team": {
        "name": "Slack Pickleball Team",
        "id": "T9TK3CUKW"
    "enterprise": {
        "name": "slack-pickleball",
        "id": "E12345678"
    "authed_user": {
        "id": "U1234",
        "scope": "chat:write",
        "access_token": "xoxp-1234",
        "token_type": "user"

If you requested scopes for a user token, you'll find them with a user access token under the authed_user property.

One more suggestion: show the user a nice message once they are redirected and you successfully gain an access token β€” or, if there's been an error, report that error to the user. The reason the user is redirected back to your app at the end of OAuth is for transparency purposes: the user deserves to know the end of the story, whether your app was installed successfully or not.

More about tokens

Using tokens

The best way to communicate your access tokens β€” also known as bearer tokens β€” to Slack is by presenting them in a request's Authorization HTTP header where the full value, including "Bearer", is case-sensitive. This approach is required when using application/json with a write method.

GET /api/conversations.list?limit=50
Authorization: Bearer xoxb-1234-abcdefgh

Alternatively, you may send the token as a POST body attribute of the application/x-www-form-urlencoded variety.

POST body:

POST /api/conversations.list
Content-type: application/x-www-form-urlencoded

Revoking tokens

OAuth tokens do not expire. If they are no longer needed, they can be revoked. Revocation of an OAuth token happens if a workspace owner fully uninstalls the app, a user individually removes their configurations, or the account of the user who initially authenticated the Slack app is deactivated.

API access tokens are revoked via the auth.revoke method. After that happens:

  • The bot token no longer works.
  • The bot user is removed from the workspace.
  • Slash commands associated with the bot token will be removed from the workspace if no user tokens for the same app exist and carry the commands scope.
  • Incoming webhooks that were installed and associated with the bot token will be removed.
  • If no user tokens for the same app exist, the app will appear to be uninstalled from the workspace.

Storing tokens securely

Store your application's credentials and user tokens with care. Restrict Web API access to only IP addresses you trust by allowlisting specific IP addresses. Read up on best practices for security.

Creating a classic Slack app

Discontinuing new classic Slack app creation

You won't be able to create new classic Slack apps or legacy custom integration bot users anymore after June 4, 2024. Learn how this may impact you and your team.


Below are some errors you may encounter and reasons for encountering them:

  • bad_redirect_uri: Occurs when there are multiple redirect_url parameter values configured and they do not match.
  • invalid_scope: Occurs if requesting a non-existent scope or requesting a set of scopes that are in conflict with each other (e.g. SIWS user scopes cannot be combined with non-SIWS user scopes).
  • invalid_team_for_non_distributed_app: Occurs when attempting to install/authorize an undistributed Slack API app on a team where the app was not created.
  • scope_not_allowed_on_enterprise: Occurs when attempting to install an app on an Enterprise Grid org containing scopes that are not org-compatible.
  • unapproved_scope: Occurs if attempting to install a published app for which the requested scopes aren't approved either because they're still in review for that app, or they weren't yet submitted for review by the app developer.
Recommended reading