This guide covers token rotation for Slack apps, which use granular permissions. You'll learn how to exchange your access token for a refresh token and an expiring access token.
With token rotation, you'll provide an extra layer of security for your access tokens.
An access token represents an installation of your Slack app. Without token rotation, the access token never expires. With token rotation, it expires every 12 hours.
An OAuth flow with token rotation involves exchanging one expiring access token for a new one, using an additional token: the refresh token. The refresh token is then revoked, and a new refresh token is used to exchange the new expiring access token when it expires.
New access and refresh tokens need to be rotated in throughout the lifespan of the app for it to continue to function.
Access token types
For Slack apps, the access token types that may be refreshed are granular bot or user tokens.
If you don't have a Slack app already, that's okay! Click on the button below to begin the process of creating one:
Fill out your App Name and select the Development Workspace where you'll play around and build your app. Don't fuss too much over either field—no matter what workspace you select, you'll still be able to distribute your app to other workspaces if you choose.
If you've just made your app, or if your Slack app isn't set up with our new OAuth V2, head over to our guide on Installing with OAuth. We'll wait right here for you.
If you use Bolt to develop your app, your job will be a whole lot easier. Token rotation is automatically handled in the Bolt frameworks for building Slack apps. All flavors of Bolt have versions that support token rotation.
Framework | Setup with token supported version |
---|---|
Bolt for Java | implementation("com.slack.api:bolt-jetty:1.9.+") |
Bolt for JavaScript | npm i @slack/bolt@3.5 |
Bolt for Python | pip install "slack-bolt>=1.7" |
Whether you're using an SDK or not, continue to turn on token rotation.
Before you turn on token rotation, consider how you're going to test your implementation. You don't want all your access tokens to expire before you've successfully figured out how to refresh them.
If your app is not published in the Slack Marketplace, token rotation is enabled via the OAuth & Permissions section of your app settings.
If your app is published in the Slack Marketplace, now is a good time to follow the advice in our guide to testing Slack Marketplace apps. Apps published in the Slack Marketplace can have token rotation enabled via the Published App Settings section of your app settings.
And if you're using a Bolt app, this is your stop! You're all good to go. If not, keep reading. The next section is just for you.
A Slack app implemented with OAuth will already have a long-lived access token. You need to call the oauth.v2.exchange
method to exchange that long-lived access token for a refresh token and an expiring access token.
You'll need your app's client_id
and client_secret
as well, which can be found under "App Credentials" within the specific app's "Basic Information" page.
Here's a sample call:
POST /api/oauth.v2.exchange
HOST slack.com
Content-Type: application/x-www-form-urlencoded
client_id=60503450.61416
client_secret=8bc5fc53901afc11c
token=xoxb-1234-...
Either a granular bot token or user token may be exchanged for a refresh token and expiring access token. You won't be able to exchange the same access token for a refresh token more than once.
After you refresh your short-lived credentials for the first time, we'll expire your original long-lived access token. Please don't try to revoke it yourself using auth.revoke
, or you'll end up making the user redo the whole OAuth installation process (yikes!). Instead, just call auth.test
to make sure the original token won't work anymore. Keep in mind that this applies to both user and bot tokens, so make sure to repeat the OAuth process to get your hands on fresh credentials.
Here's a sample response from oauth.v2.exchange
when exchanging a bot token:
{
"ok": true,
"access_token": "xoxe.xoxb-1-...", // New access token
"expires_in": 43200, // 12 hours
"refresh_token": "xoxe-1-...", // New refresh token
"token_type": "bot",
"scope": "commands,incoming-webhook",
"bot_user_id": "U123456",
"app_id": "A123456",
"team": {
"name": "Slack Softball Team",
"id": "T123456"
},
"enterprise": {
"name": "slack-sports",
"id": "E12345678"
},
}
Notice that your access_token
now has a new xoxe.
prefix. The access token's lifespan is based on the expires_in
field. This field defines the number of seconds until the access token you've received expires. It will always expire in 43,200 seconds, which is 12 hours.
The response will also have a refresh_token
.
You now have your first set of rotatable tokens!
Any time you implement OAuth with your Slack app, whether token rotation is enabled or not, the last step of the flow requires you to call the oauth.v2.access
method. The only difference with token rotation is that you'll be calling the method throughout your app's life to get new tokens.
In order to refresh a token, make a call to oauth.v2.access
, setting the new grant_type
parameter to your refresh token:
POST /api/oauth.v2.access
HOST slack.com
Content-Type: application/x-www-form-urlencoded
client_id=60503450.61416
client_secret=8bc5fc53901afc11c
grant_type=refresh_token
refresh_token=xoxe-1-...
Note that client_id
and client_secret
are still required for this call as well.
When you have turned on the token rotation toggle, your app will receive additional data from oauth.v2.access
. Expect a response that contains the following new fields mentioned earlier:
...
"expires_in": 43200, // 12 hours
"refresh_token": "xoxe-1-...",
...
You can receive refresh tokens for both user tokens and bot tokens in the same oauth.v2.access
response (only applies to the initial oauth.v2.access
response before token rotation is enabled).
If you make use of a user token, expect those two new fields along with your access token in the authed_user
object of the response:
"authed_user": {
"id": "U1234",
"scope": "chat:write",
"access_token": "xoxe.xoxp-1-1234-...",
"expires_in": 43200, // 12 hours
"refresh_token": "xoxe-1-..."
"token_type": "user"
}
Use the new refresh_token
when you need to refresh the tokens once again. Schedule a task to refresh your access token before the expires_in
time. If you don't refresh your access token in time, you'll receive an error when you make an API call with the expired access token.
Store the refresh token as you would an access token, in a database or secure datastore (not in code). Refresh tokens are designed to be used once. After calling oauth.v2.access
, the refresh token you used is revoked after a short grace period.
Calling oauth.v2.access
will not immediately invalidate your existing access token. If you need to immediately revoke an access token, you can call auth.revoke
.
2 active token limit
If you refresh your credentials repeatedly before expiration (e.g. by calling oauth.v2.access
multiple times for the same token within a 12 hour period), we will enforce a limit of 2 active tokens. If more than 2 tokens exist after the refresh, the oldest additional token will be revoked.
Once you've successfully refreshed an access token, congratulations! You're now developing with a more secure app that makes use of token rotation.
You may also create a new app that makes use of token rotation using app manifests.
Add the following to your app manifest YAML to enable token rotation:
settings:
token_rotation_enabled: true
Slack APIs provide multiple ways to undo Slack installations. With apps.uninstall
, behavior is the same regardless of whether the app uses token rotation. The app is uninstalled and all tokens associated with the installation are revoked.
auth.revoke
is used to revoke a single token of an installation. When used on an app without token rotation, it usually revokes the authorization associated with it, meaning that the user or team that had the app installed needs to reinstall it.
For apps with token rotation, auth.revoke
will revoke a single token (a refresh token, a bot access token that expires, or a user access token that expires) without changing the underlying installation. Events will still be delivered and new tokens may still be generated in the UI.