Go to Slack

Rotating and refreshing credentials

Developer preview

This feature is exclusive to our workspace apps developer preview.

For optimal security, workspace apps can enable auto-expiring, short-lived access tokens; then use long-lived refresh tokens to generate them programmatically.

We call this OAuth 2.0-based process token rotation, and all distributed workspace apps must implement it. Learn more about this requirement.

There and Back Again: a story of tokens

The OAuth 2.0 flow begins with a user interacting with your app, and ends with your app authorized to access Slack resources in a way dictated by the user.

The permissions that your app gains encapsulate within an object: an access token. The access token is your app's ring of power, allowing you dominion over the data, conversations, history, and other helpful machinations users have bestowed upon it.

By having an access token's powers regularly expire, the danger of the token falling into the wrong hands is diminished. But in order to retain those powers, your app needs a way to routinely request a fresh access token.

Refresh tokens are the key ingredient to rotating access tokens.

What are refresh tokens?

The OAuth 2.0 spec defines a refresh token to allow your app to seamlessly rotate its access tokens. That way, your app can continue on its merry path, regardless of what kind of adventures might strike your individual access tokens.

Why expire and rotate tokens?

When used in addition to basic OAuth safety techniques, token expiration and rotation features protect your app, and therefore your users and their workspaces, in multiple ways:

While we already recommend keeping tokens and client credentials secure and secret, automatic token expiration and token rotation protect workspaces, users, and your app when it's needed most.

  • The consequences of losing a token are shorter-lived: short-lived tokens expire every sixty minutes. Once expired, they can't be used again.
  • You don't have to wait for a token to expire to rotate it. Your app can rotate and expire tokens continuously without downtime.
  • Your app can work with greater independence when decomposed into microservices or multiple deployments: each instance can retain its own short-lived tokens independently.

It remains essential that you protect all types of tokens and secrets. Keep them secret. Keep them safe.

Who should use token rotation

All distributed workspace apps must use token rotation, whether submitted to the app directory or not.

For internal apps built just for a single workspace, the choice is yours. Token rotation may represent a slight additional hurdle to getting your app off the ground; however, it's a critical way to maintain appropriate security around your access token. In other words: we strongly recommend all workspace apps to use token rotation.

Installing a workspace app on multiple workspaces within the same Enterprise Grid organization requires enabling distribution. Therefore, token rotation is required for all apps targeting multiple workspaces in an organization.


Getting started with token rotation

By default, your workspace app is setup to use a single long-lived workspace token per workspace.

To begin using refresh tokens and expiring access tokens, you must first enable token rotation for your app.

Enabling token expiration and refresh tokens

Navigate to app management and enter your workspace app's configuration settings. In the OAuth & Permissions section, you'll find a Token Expiration setting and toggle.

OAuth settings in app mgmt displaying the toggle

After confirming, new tokens generated by your app will expire in 60 minutes.

Getting a refresh token

For an app in your own workspace

When apps are distributed beyond their home workspace, they need to use the OAuth flow to programmatically generate access tokens for each new workspace.

After enabling token expiration, the initial OAuth installation flow will also generate the refresh tokens your app will need for token rotation.

OAuth settings in app mgmt displaying the refresh token field

Once you've obtained the refresh token, you still must interface with oauth.access to obtain a new short-lived access token. This process is performed continuously, every time the token expires.

For apps distributed to multiple workspaces

Request a refresh token during the initial OAuth installation flow for your workspace app.

In all versions of OAuth, when a user authorizes an app, it receives a temporary code. The app then calls oauth.access to exchange this code for an access token.

When using token rotation, you'll also receive a long-lived refresh token and the expiration time of your short-lived access token.

Here's where the story begins to diverge. Workspace apps will now receive two distinct tokens from oauth.access in exchange for the temporary code: a long-lived refresh token (xoxr-...), and a short-lived access token (xoxa-2-...).

The short-lived access token still functions exactly the same way the old token did, allowing your app to call API methods. However, it expires after a fixed amount of time indicated in the expires_in parameter. After that, it will need to be refreshed using the refresh token.

Here's a bit more detail on your new request to oauth.access. It might look something like:

POST /api/oauth.access
Host: slack.com
Content-Type: application/x-www-form-urlencoded

client_id=60503450.61416
client_secret=8bc5fc53901afc11c
code=605034560.23854611 // obtained from redirecting the user to Slack
grant_type=authorization_code // optional parameter, defaulting to authorization_code

Then, your app will receive a response that looks like:

{
    "access_token": "xoxa-2...",
    "token_type": "app",
    "refresh_token": "xoxr-...",
    "expires_in": 3600,
    // ... other fields
 }

A full description of these fields can be found in the oauth.access reference doc.

Handling automatic token expiration

Your access tokens will expire. It's up to you to refresh them when you're ready — probably instantaneously but you can take your time if you like and don't have anything you need to do with it.

1. Detecting token expiration

Once you've turned on automatic expiration, you'll need to handle the case where an access token you're using has expired.

The best way to manage token expiration is to essentially persist the expiration time and count down the seconds until your token is expired, then refresh.

If you'd rather not cache and manage the expires_in value, you can expect the error code invalid_auth when invoking a method with an expired access token. The error code is purposefully vague; it doesn't give potential attackers information about why the authentication was invalid.

One way to track whether a token has expired versus having been revoked is subscribing to the tokens_revoked event.

2. Handling expired tokens

Because the invalid_auth error means more than one thing, you might not know for sure whether you need to refresh the token unless you're tracking the expires_in value. With token rotation on, you may as well try to refresh the token and assume it's expired.

Use the oauth.access method with your token set to your refresh token value and grant_type set to refresh_token.

Note that the grant_type represents the type of auth being passed to the method, not the type of token that will be returned from it.

For example, you might post the following to the oauth.access endpoint:

POST /api/oauth.access
Host: slack.com
Content-Type: application/x-www-form-urlencoded

client_id=60503450.61416
client_secret=8bc5fc53901afc11c
grant_type=refresh_token
refresh_token=xoxr-...

Then your app will receive a response containing a new access_token as well as the team_id it corresponds to. You should store a mapping of which access_token is currently being used for which team_id if you want to safely handle multiple workspaces in your app.


Token and installation management

You can control token revocation and completely uninstall your app from a workspace using two dedicated Web API methods.

Manually revoking tokens

Too manually revoke an access token — maybe because you think it might be compromised — use the existing auth.revoke method with your refresh token.

A typical API call might look like:

GET /api/auth.revoke
Host: slack.com
Content-Type: application/x-www-form-urlencoded
token=xoxr-your-refresh-token

And the response might appear as:

{
    "ok": true,
    "revoked": true
}

Note that this method only revokes an access token. It does not uninstall the app.

Uninstalling workspace apps

The apps.uninstall method revokes all of the access tokens and refresh token associated with an app, uninstalling the app completely.

The method requires your app's client id and client secret as well as an access token.

A typical call might look like:

GET /api/apps.uninstall
HOST slack.com
Content-Type: application/x-www-form-urlencoded

client_id=12345.5678
client_secret=abcd
token=xoxa-... // also accepts xoxr-...

A typical {"ok":true} response returns when the call is successful.

You may also want to gracefully handle the case where your app is uninstalled. API methods will return a workspace_app_uninstalled error code if your app's install has been revoked.

Best practices

  • Store the Client Secret separately from your Refresh Token. That way, these two separate long-lived secrets serve as a form of two-factor authentication, providing a double barrier against someone gaining power over your app.
  • Expect and handle invalid_auth error codes from API methods. This error code means you must refresh your access token. Even if your app checks a TTL to determine when to refresh your automatically expiring token, you should still handle the invalid_auth case as well, because tokens may be expired manually.
  • Token rotation doesn't make it safe to store access tokens client-side.

SDK support

Robust token rotation implementations will come free with the use of our Slack Developer Kits. Initialize your Node (and, coming soon: Python) Slack Client with a refresh token, and the SDK pretty much takes care of the rest.

Learn more in node-slack-sdk's refresh token docs.

Limitations

  • We return the invalid_auth error code in several different circumstances, including when an access token are revoked. The error is purposefully vague to avoid leaking information to potential attackers. You should assume that, if you receive this code from an API method, you must refresh your access token using your refresh token.
  • A quick note on rate-limiting: oauth.access follows a custom rate-limiting scheme for the refresh case only. After your app has received its refresh token, it may call the endpoint to gain a new access token at a rate of 10 calls per minute, with an occasional burst of up to 50.