Migrating App Permissions and Access Tokens

// By Taylor Krusen • Sep 17, 2020

Introducing Scoped Apps

We recently launched several permissions enhancements. You can read about them in the OAuth Guide or in the blog post, Now Available: Scoped Apps and Enhanced Permissions. The major changes to be aware of are the introduction of short-lived tokens, scopes, PKCE, and refresh tokens. For now, our App Console supports both legacy and scoped app creation, but may be turned off soon as we prepare to retire long-lived tokens on September 30th, 2021. This means that:

  • You should review your apps permission tab to transition to scopes. (This does not require code changes).
  • You should ensure your app works with short-lived access tokens. (This may require code changes).

Updating Permissions

When you go the Permissions tab in an app’s settings, the scopes will be pre-selected based on your app’s legacy access type. For example, apps using the Business API with Team auditing will have team_info.read, members.read, groups.read, and events.read already selected. Apps using the User API will have all user scopes pre-selected.

You can click through without making changes and your app will continue working. However, we strongly recommend deselecting the scopes your app doesn’t need, which results in better overall security and asking for less permissions from your users.

Determine required scopes

Make a list of endpoints used by your app. Look at each endpoint in the HTTP Reference documentation and record the “Required Scope”.

Screenshot of the "required scope" field for an endpoint in the Dropbox API documentation
Required scope for an endpoint in the API docs

For example, pretend we’re migrating an app for an online photo editing tool. For each endpoint used by the app we're going to record the corresponding scope.

Endpoint Required Scope
/users/get_current_account account_info.read
/files/list_folder (and /continue) files.metadata.read
/files/get_thumbnail files.content.read
/files/download files.content.read
/files/upload files.content.write

If you ensure that your app’s scopes match your list, then your app will have the exact permissions it needs to access those endpoints. API calls to an endpoint without the appropriate scopes will throw an error.

Programmatically set scopes

After migrating, you can test your app with a specific group of scopes by passing them in the authorization URL. This approach can be used to test groups of scopes before deselecting the ones that aren’t needed.


Migrate permissions to scopes

Inside the App Console, go to the Settings page of app using the legacy permission model and click the Permissions tab. Note the message in light blue with details about the migration process. Deselect the scopes that your app is not using. Exercise caution when deselecting scopes as you can break functionality that your app depends on. We recommend auditing your app for required scopes before deselecting the ones you don’t need.  Additional scopes can be added or removed later as needed.

Screenshot of the Permissions tab in app settings for a Dropbox app
Permissions tab of a Dropbox app's settings page

Click Migrate then Confirm. Note that this change does not impact existing tokens. Test your scopes by going through an authorization flow. Way to go—you’ve migrated your app to use scopes! Next, we recommend migrating to short-lived tokens as long-lived tokens will be deprecated in the future.

Updating Access Token Type

If your app handles errors with 401 status correctly and only calls the Dropbox API when users are interacting with it, then it shouldn’t need any code changes. If your app doesn’t properly handle 401 errors or needs to interact with the Dropbox API without user input (“offline” access), then it may require code changes.

Testing short-lived access tokens with token_access_type

Before migrating your app to short-lived tokens, we recommend testing them in your app. You can programmatically issue short-lived tokens with a small adjustment to your code—including token_access_type=online in your authorization URL.


We recommend starting with this approach during migration, then, once you’re confident in your app’s behavior, update the default access token type to short-lived in the App Console. You can find more information about setting up the right authorization flow for your app in the OAuth Guide.

Handle authorization errors

When a user tries to access your app with an invalid token, redirect them to the authorization URL you use in your OAuth flow. If the user has already authorized the app (and is logged into Dropbox), then a new short-lived is issued and they’re redirected to your app without any input from the user. This process will result in more re-authorization flows than before, but will have minimal impact on the end user experience.

If your app only calls the Dropbox API when the user is actively interacting with the app (online access) and follows the OAuth best practice of prompting for re-authentication on a 401 error, then your app should not not require code changes to support short live tokens.

Implement refresh tokens

For apps that:

  • Want long-term access regardless of whether a user is present (i.e. a mobile app that stays logged in)
  • Want to interact with the Dropbox API when a user isn’t actively interacting with the app (“offline” access)

We offer a long-lived refresh_token that can be used to request a new, short-lived access token.

Request a refresh_token as part of your access token payload by declaring the token access type as offline (token_access_type=offline) as a parameter in your authorization URL:


Now, complete your authorization request to /oauth2/token

curl https://api.dropbox.com/oauth2/token \
    -d code=<AUTHORIZATION_CODE> \
    -d grant_type=authorization_code \
    -d redirect_uri=<REDIRECT_URI> \

The resulting payload contains a refresh_token:

    "uid": "267161268", 
    "access_token": "Your_Access_token", 
    "expires_in": 14399, 
    "token_type": "bearer", 
    "scope": "files.content.read files.metadata.read sharing.read sharing.write", 
    "refresh_token": "LwlUmqpmGqgAAAAAAAAEYgRoVJoei4u9cC7cDHFBAp0Kkp2JNciPxQpNWGY", 
    "account_id": "dbid:AABuTtSGJM0ME3t4m85i1o3XqnmXvwH5I-A"

Now, when you request a new token from the /oauth2/token endpoint, set the grant_type to refresh_token and provide your refresh_token as a parameter:

curl https://api.dropbox.com/oauth2/token \
    -d grant_type=refresh_token \
    -d refresh_token=<YOUR_REFRESH_TOKEN> \

Update default token type

[Update: Dropbox is no longer offering the option to create new long-lived access tokens, so the Access token expiration drop-down is no longer available.]

Inside the Settings page (accessed via the App Console) of a legacy app, locate the section for OAuth 2 settings. Newly created scoped apps will default to short-lived tokens.

Access token expiration settings in the OAuth 2 field of a Dropbox app's settings page
Access token expiration settings

Click the Access token expiration drop-down and select Short-lived. Now your app is using short-lived access tokens by default! Note that short-lived tokens will expire after a period of time which is “short”, but generally long enough for a reasonable web session. The amount of time that an access token is valid is returned in the expires_in parameter of the access token payload. If your app needs “offline” access, then refer to the Implement refresh tokens section above.

Retiring Legacy Tokens

On September 30th, 2021, Dropbox will retire the creation of long-lived access tokens — resulting in all new tokens being short-lived. For online-only apps that already handle re-authentication, users may experience more prompts for re-authentication. Apps that require background (“offline”) access but have not yet implemented refresh tokens will be impacted.

Getting Help

We’re here to help! Do you have some unanswered questions about the migration process? Are there specific resources or examples that would be useful to you? Please let us know by posting in the scopes discussion thread on our developer forum. If you need private, direct help, then please reach out using the support request form
Build with Dropbox today at www.dropbox.com/developers.

// Copy link