OAuth 2.0 Access Modes: Online vs. Offline
Dropbox's API has moved to short-lived access tokens, with refresh tokens available as an option. Understanding when and how to use refresh tokens is essential for apps that need ongoing access. For most applications, the official Dropbox SDKs handle the OAuth authorization flow automatically, so check the SDK documentation first. If you're implementing the flow directly against the Dropbox OAuth endpoints, the details below apply.
When Online Access Suffices
"Online" access is appropriate when your app only needs to interact with a user's Dropbox while the user is actively present. A web app that touches Dropbox files only during active user sessions fits this model.
With online access, the app receives a short-lived access token after the user completes authorization. When that token expires, the app simply sends the user through the authorization flow again. For users who have already authorized the app, this reauthorization is usually a single click or happens automatically via redirect.
The Online Flow
First, direct the user to the /oauth2/authorize endpoint with token_access_type=online:
https://www.dropbox.com/oauth2/authorize?client_id=<APP KEY>&response_type=code&token_access_type=online&state=<STATE>&redirect_uri=<REDIRECT URI>
After authorization, the user is redirected back with an authorization code:
<REDIRECT URI>?code=<AUTHORIZATION CODE>&state=<STATE>
Next, exchange that code for an access token via the /oauth2/token endpoint:
curl https://api.dropbox.com/oauth2/token \
-d code=<AUTHORIZATION CODE> \
-d grant_type=authorization_code \
-d client_id=<APP KEY> \
-d client_secret=<APP SECRET> \
-d redirect_uri=<REDIRECT URI>
The response contains the access token and its expiration:
{"access_token": "<ACCESS TOKEN>", "expires_in": "<EXPIRATION>", "token_type": "bearer", "scope": "<SCOPES>", "account_id": "<ACCOUNT ID>", "uid": "<USER ID>"}
Use the token as a Bearer credential in the Authorization header for API calls:
curl -X POST https://api.dropboxapi.com/2/users/get_current_account \
--header "Authorization: Bearer <ACCESS TOKEN>"
Offline Access with Refresh Tokens
Apps that must operate in the background, receiving updates or performing work when the user isn't present, need "offline" access. This requires requesting a refresh token alongside the short-lived access token.
The Offline Flow
Begin authorization by setting token_access_type=offline in the /oauth2/authorize URL:
https://www.dropbox.com/oauth2/authorize?client_id=<APP KEY>&response_type=code&token_access_type=offline&state=<STATE>&redirect_uri=<REDIRECT URI>
The redirect response is the same as in the online flow, carrying a one-time authorization code.
Exchange the code at the /oauth2/token endpoint:
curl https://api.dropbox.com/oauth2/token \
-d code=<AUTHORIZATION CODE> \
-d grant_type=authorization_code \
-d client_id=<APP KEY> \
-d client_secret=<APP SECRET> \
-d redirect_uri=<REDIRECT URI>
This response now includes a refresh token:
{"access_token": "<ACCESS TOKEN>", "expires_in": "<EXPIRATION>", "token_type": "bearer", "scope": "<SCOPES>", "refresh_token": "<REFRESH TOKEN>", "account_id": "<ACCOUNT ID>", "uid": "<USER ID>"}
Store the refresh token securely. It can be reused indefinitely—it doesn't expire automatically, though it can be revoked at any time.
Use the short-lived access token for API calls until it expires:
curl -X POST https://api.dropboxapi.com/2/users/get_current_account \
--header "Authorization: Bearer <ACCESS TOKEN>"
When the access token has expired, request a new one by sending the refresh token to the /oauth2/token endpoint:
curl https://api.dropbox.com/oauth2/token \
-d refresh_token=<REFRESH TOKEN> \
-d grant_type=refresh_token \
-d client_id=<APP KEY> \
-d client_secret=<APP SECRET>
The response yields a fresh short-lived token:
{"access_token": "<NEW ACCESS TOKEN>", "expires_in": "<EXPIRATION>", "token_type": "bearer"}
The cycle of using the access token and refreshing it with the refresh token can be repeated programmatically as needed.
Key Implementation Notes
response_type=codeis required for offline access. The legacyresponse_type=tokenflow does not support refresh tokens and is no longer recommended.- Server-side apps should use
response_type=code; client-side apps should useresponse_type=codecombined with PKCE. Both modes support offline access. - A redirect URI is optional with
response_type=code, but consistency matters: if you setredirect_urion the authorize URL, you must pass the same value when exchanging the authorization code withgrant_type=authorization_code. If you omit it during authorization, omit it during the exchange as well. When usinggrant_type=refresh_token, do not includeredirect_uri. - App key, app secret, authorization code, access token, and refresh token are distinct credentials with different lifetimes and purposes. Authorization codes are single-use and short-lived; access tokens expire quickly; refresh tokens are long-lived unless revoked.
- Tokens can be revoked by the user via the Connected apps page, by team admins via the Team apps page, or programmatically by the app using the
/2/auth/token/revokeendpoint, which also revokes any associated refresh token. - Refresh tokens are scoped to a specific app and user. If you maintain multiple app registrations, track which app each refresh token belongs to—using the wrong app key/secret with a refresh token will fail.



