Installing with OAuth

Modern Slack apps are installed with a V2 OAuth 2.0 flow.

We're sorry about the double V2s: 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 call it OAuth and drop all the 2s.

The OAuth flow for Slack apps works exactly the same way as the OAuth flow for classic Slack apps. Only a few details have changed slightly: URL and method names have gained a v2, and the shape of the OAuth access response now puts bot access tokens first.

We've created a version 2 of the OAuth flow because it provides more granular Slack scopes, especially for bot users. With the new OAuth flow, your app can act with its own identity, instead of acting on behalf of users—all without requesting excessive permissions that could cause installs to be rejected.


OAuth lets a user in any Slack workspace install your app. At the end of OAuth, 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 (methods, events, and features) your app can open.

But first, let's talk about the elephant in the room: implementing an OAuth flow can feel discouragingly hard.

Here are some things that feel hard about OAuth:

  1. There are a lot of steps, with multiple participants.
  2. Your app has to be able to redirect a user to Slack, and your app also has to handle a user being redirected back to the app.

Here are some corresponding, comforting facts:

  1. There are a lot of steps, but... Your app only has to worry about three steps to make OAuth work: Asking for scopes, waiting for a user to give the okay, and exchanging a temporary code for a full access token.
  2. Your app has to handle redirects, but... 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'll have a link that can initiate an OAuth install.

You can even turn that link into an Add to Slack button, as we'll show later.

Obtaining access tokens with OAuth 2.0

Your app gains an access token in three steps:

  1. Asking for scopes.
  2. Waiting for a user to approve your requested scopes.
  3. Exchanging a temporary authorization code for an access token.
Negotiating tokens with Slack's OAuth 2.0 authorization flow

Asking for scopes

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

To ask for 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 separate OAuth flows.

Include both your app's Client ID found in the App Management page, and a comma-separated list of scopes: scope=incoming-webhook,commands.

The full redirect URL will look something like:,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 (say, to act on behalf of a user), provide a user_scope parameter with requested user scopes instead of, or in addition to, the scope parameter.

Consider the following: progressive permissions
Each trip through installation can result in additive scopes. For example, if a user installs your app into a workspace while you request channels:history but then installs your app again while you ask for channels:read then 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 you ask for 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.

If there are multiple Redirect URL values configured in the App Management page, and no redirect_uri parameter is sent, then the OAuth flow will use the first Redirect URL listed on the App Management page.

You can even do both: use the redirect_uri parameter in your oauth/v2/authorize redirect, and configure a Redirect URL in the App Management page! If you do choose both, your redirect_uri must match, or be a subdirectory, of a Redirect URL configured in your App Management page. A Redirect URL can not contain an anchor (#).


GOOD redirect_uri:

Also, consider including the optional state parameter. The state parameter should be used to avoid forgery attacks—pass in a value that's unique to the user you're authenticating and check it when you receive a temporary authorization code.

How the team parameter behaves

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 in the above step.

Exchanging a temporary authorization code for an access token

If all goes well, a user goes through the Slack app installation UI and okays your app with all the scopes it requests. After that happens, 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 have to exchange the code for an access token. You'll do this by calling the oauth.v2.access method:

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

Note: If you initiate an install with the v2/authorize URL, it must be completed with oauth.v2.access, not the old oauth.access method.

After you complete your access call, Slack sends you an HTTP request response containing an access token. It looks 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 Softball Team",
        "id": "T9TK3CUKW"
    "enterprise": {
        "name": "slack-sports",
        "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.

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, if users individually remove their configurations, or if the account of the user who initially authenticated the Slack app is deactivated.

With that, you've reached the OAuth finish line. After you show your installing user a joyful success message, your app can get to work.

Create an Add to Slack button

Encapsulate the start of your OAuth flow into a neat and tidy "Add to Slack" button by using our generator below.

Looks like you don't have any apps yet.

Create an App

Extra credit

A little motivation

Here's a pop quiz: 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, at the same time. It's like showing a passport to enter a new country: your visa (auth code) states a fact about the person described in the passport, but you still need the photo ID (Client Secret, in this case) to prove that you're the rightful owner of the passport.

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

Perspectival scopes

Nearly all app actions are now performed from the perspective of the identity associated with your token: that's a bot user for a bot token, or regular user for a user token. Perspectival scopes (for example, chat:write:user, chat:write:bot, files:write:user, files:write:bot) are disappearing. Just use chat:write and files:write.

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:

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

This approach is required when using application/json with a write method.

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

We no longer allow new apps to send the token as a querystring.

Revoking tokens

API access tokens are still revoked in the same way, via the auth.revoke method. When 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. Read our article on safely storing credentials.

Restrict Web API access to only IP addresses you trust by allowlisting specific IP addresses.

Creating a classic Slack app

If you still need to create a classic Slack app, either to use the rtm.connect method, or for any other reason, click here:

Create a classic Slack app

You can continue to distribute it via the first version of OAuth 2.0.

Recommended reading