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.
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="https://slack.com/oauth/v2/authorize?scope=incoming-webhook&client_id=33336676.569200954261">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 AppYour app obtains an access token in three steps:
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.
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 https://slack.com/oauth/v2/authorize
. If you're developing a GovSlack app for use by public sector customers, redirect users to https://slack-gov.com/oauth/v2/authorize
.
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:
https://slack.com/oauth/v2/authorize?scope=incoming-webhook,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:
redirect_uri
in this step.redirect_uri
in the previous step, and adds a verification code to that URL.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 (#
).
REDIRECT_URL: https://example.com/path
GOOD redirect_uri: https://example.com/path
GOOD: https://example.com/path/subdir/other
BAD: http://example.com/bar
BAD: http://example.com/
BAD: http://example.com:8080/path
BAD: http://oauth.example.com:8080/path
BAD: http://example.org
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.
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.
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 https://slack.com/api/oauth.v2.access
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.
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
token=xoxb-1234-abcdefgh&limit=50
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:
commands
scope.Additionally, for Slack apps using granular permissions, you can exchange your access token for a refresh token and an expiring access token with token rotation.
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.
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.