---
name: dropbox-oauth-app
description: Creates or signs in to a Dropbox account and registers a Dropbox app in the App Console to obtain an OAuth2 app key and app secret (client ID and client secret) — with the irreversible App folder vs Full Dropbox access-type choice, redirect URIs, scoped permissions, `token_access_type=offline` for refresh tokens, and the development-to-production approval path. Use when asked to get Dropbox OAuth credentials, create a Dropbox app, set up a Dropbox developer account, rotate a Dropbox app secret, or fix a Dropbox OAuth error such as a missing refresh token, an access token that dies after a few hours, a redirect URI mismatch, a missing-scope 401, or an app that suddenly stopped linking new users. For any other vendor's developer portal, use that vendor's skill instead.
---

# Dropbox OAuth2 App Registration

Get a working Dropbox OAuth2 client — a Dropbox account, an app in the App Console, redirect URIs, scopes, and the
**app key** and **app secret** (Dropbox's names for `client_id` and `client_secret`) — for a platform that connects
many customers' Dropbox accounts.

Three things in this portal are expensive to get wrong, and two of them are silent:

1. **The access type — App folder vs Full Dropbox — cannot be changed after the app is created.** Dropbox's own
   documented remedy is to delete the app and create a new one, which means a new app key and every existing customer
   re-authorizing. This is the single most costly mistake available here. Read §3 before clicking Create app.
2. **You only get a refresh token if the authorize URL carries `token_access_type=offline`.** Omit it and everything
   looks fine: the flow succeeds, you get an access token, you make a call. About four hours later the connection is
   dead and there is nothing to refresh with. §8.
3. **Development apps freeze at 50 linked users**, and the production review is not even looked at before you reach
   50. Plan the approval before you need it, not the week the freeze lands. §6.

## Inputs to collect before you start

Ask in one batch. Never invent.

| Input | Notes |
| --- | --- |
| **App name**, publisher, description, website, icons | Shown on the consent screen and used in production review (§6) |
| **Which Dropbox account owns the app** | An existing one, or a new sign-up (§2) |
| **Access type: App folder or Full Dropbox** | Irreversible — decide deliberately (§3) |
| **Personal/user app or team (Business API) app** | A different app type with different scopes (§3) |
| **Redirect URIs** | Every callback host your platform serves (§4) |
| **Scope set** | Exactly what the connector calls (§5) |
| **Does the client send `token_access_type=offline` and store the refresh token?** | Blocking — see §8 |
| **Expected user count and timeline** | Decides how urgent production approval is (§6) |

## Quick Start

1. Confirm a **new app** is needed — existing connections are bound to the current app key (§1).
2. Sign in to, or create, the Dropbox account that will own the app (§2).
3. Choose the access type **deliberately**, then create the app in the App Console (§3).
4. Register **every** redirect URI, exactly (§4).
5. Enable only the scopes the connector calls, on the Permissions tab (§5).
6. Decide when to apply for production status, and what the form will need (§6).
7. Copy the app key and app secret from the Settings tab (§7).
8. Confirm the client sends `token_access_type=offline` and stores the refresh token (§8).
9. Verify end-to-end with a second account, including a refresh after expiry (§9).
10. Hand the credentials over — never commit them (§10).

## Platform state (verified 2026-09-20 — re-verify before trusting)

- The developer portal is **www.dropbox.com/developers**, and apps are managed in the **App Console** at
  `https://www.dropbox.com/developers/apps`. The documentation now lives under **docs.dropboxapi.com**;
  `developers.dropbox.com/oauth-guide` still resolves and redirects there.
- The App Console app page has **four tabs: Settings, Permissions, Branding, Analytics.** App key and app secret,
  redirect URIs, status and the access type all live on **Settings**; scopes live on **Permissions**.
- Apps are **scoped apps**. Scopes are selected in the Permissions tab; the access-type choice (App folder / Full
  Dropbox) is separate from and orthogonal to scopes.
- **Access type cannot be edited.** The App Console documentation states plainly that to change it "you'll need to
  delete the existing app and create a new one with the desired access type."
- **Long-lived access tokens are deprecated.** Access tokens are short-lived; the documented examples return
  `"expires_in": 14400` — four hours. Refresh tokens require `token_access_type=offline` at authorize time.
- **PKCE is supported** (`code_challenge_method` of `S256` or `plain`), and is Dropbox's recommendation for clients
  that cannot keep a secret. Implicit grant still exists as a legacy option and should be disabled if unused.
- **Development mode caps at 500 total linked users, with a hard checkpoint at 50** (§6). Team/Business apps cap at
  one team plus up to 5 additional development teams.
- The OIDC discovery document at `https://www.dropbox.com/.well-known/openid-configuration` reports
  `authorization_endpoint` `https://www.dropbox.com/oauth2/authorize`, `token_endpoint`
  `https://api.dropboxapi.com/oauth2/token`, and token endpoint auth methods `client_secret_basic` and
  `client_secret_post`.

If the App Console does not look like this, stop and report what you actually see rather than clicking on.

## 1. Decide: reuse the existing app, or register a new one

A new app means a **new app key, and every existing customer connection is bound to the old one** — all of them would
have to re-authorize. Reuse the existing app for: adding a redirect URI, adding or removing a scope, rotating a
compromised secret, uploading branding, or applying for production status.

Register a **new** app only when the user explicitly wants one: a replacement for a compromised app, a separate app
for a different product, a team/Business app alongside a user app, or — the common forced case — **the access type is
wrong and cannot be changed** (§3). Note that Dropbox's own guidance is one app key per distinct app, and that
re-registering is a customer-visible re-authorization event, not a config change. Say which path you are taking first.

## 2. Account: sign in or sign up

Any Dropbox account can create apps — there is no separate "developer account" tier to apply for. Sign in at
`https://www.dropbox.com/developers` and go to the App Console.

- Use an account the **company** controls, not a personal one belonging to whoever happened to set it up. The account
  owns the app, the credentials, the production approval and the analytics.
- For **team/Business API** testing, Dropbox grants free Business development accounts by request; the request form is
  linked from the Business API overview and approval is discretionary. Start that early if you need it (§3).
- The **same account is also the first linked user** while the app is in development mode (§6).

Hand control back to the user for anything only they can do: sign-up email verification, two-step verification,
accepting the developer terms and conditions, or requesting a Business development account. Do not retry a blocked
step in a loop.

**If this session has no browser automation** (the usual case for a CLI or cloud run), do not pretend to click. Hand
the user an exact, ordered click path with the literal values to paste — the redirect URIs from §4 and the scope list
from §5 — then continue once they report back with the app key.

## 3. Create the app — and the access-type decision you cannot undo

**Settings → App Console → Create app.** The wizard asks three things, and the third is permanent.

1. **Choose an API** — the Dropbox API (user-facing) or the Business/team API path (see below).
2. **Choose the type of access you need** — **App folder** or **Full Dropbox**. See the box below.
3. **Name your app** — must satisfy the Branding Guide; names can be edited while the app is in development, but
   **once the app has production status the name is frozen** and only a support request can change it.

### The access type is permanent

| Access type | What the app can reach |
| --- | --- |
| **App folder** | A single dedicated folder created for your app inside the user's `Apps` folder. Read and write **that folder only**. Users hand you content by moving files into it. |
| **Full Dropbox** | All files and folders in the user's Dropbox, to the extent the scopes allow. |

Scopes and access type are two different limits that both apply. A `files.content.read` scope on an App folder app
reads *inside the app folder*, and nothing else — no error, just an empty or tiny view of the user's Dropbox. That is
what an under-chosen access type looks like in production: not a failure, a silence.

**It cannot be edited afterwards.** Dropbox's documented remedy is to delete the app and create a new one with the
desired access type — a new app key, and every customer re-authorizing.

So decide against the connector's actual job, not against what feels polite:

- **A connector that syncs, lists, searches or reads a customer's pre-existing Dropbox content needs Full Dropbox.**
  App folder cannot see content the app did not put there.
- **App folder is right** when the app only ever manages its own output — exports, generated documents, backups — and
  it is what Dropbox's review prefers, because it is the least privileged option.
- **Extensions require Full Dropbox**, with no App folder alternative.

If the user cannot answer this confidently, **stop and ask**. Two minutes of clarification here is worth more than
every other step in this skill combined. Also note the **App folder name** setting on the Settings tab: for App folder
apps it defaults to the app name and can be changed, but it must not be misleading to end users.

### Team / Business apps are a separate app type

An app built on the **Dropbox Business API** is created the same way but is a different animal:

- Authorization is performed by a **team administrator**, and the resulting token is associated with the **team**, not
  with the admin who clicked approve. The OAuth response carries an extra `team_id`.
- Acting as an individual member is **impersonation via headers**: `Dropbox-API-Select-User` with a `team_member_id`
  for member operations, `Dropbox-API-Select-Admin` for team-owned content. Both require the **`team_data.member`**
  scope on the token — a dependency Dropbox enforces in the Permissions tab and in the OAuth flow.
- Teams on the **team space** configuration need the `Dropbox-API-Path-Root` header to reach team content; without it,
  calls are rooted to the member's home namespace and team folders simply are not there.
- Development mode for a team app means **one team**, plus up to 5 additional development teams enabled from the app's
  page.

A team token and a user token are not interchangeable. If the platform needs both personal Dropbox accounts and
Dropbox Business teams, that is a design question for the connector's owner — surface it, do not decide it.

## 4. Redirect URIs

Register **every** callback host your platform serves, on the Settings tab under **OAuth 2 → Redirect URIs**. Dropbox
checks the `redirect_uri` you send against the registered values **at authorization time**, and the match is exact.

For Unified.to these are one per data center; confirm the current list with the platform owner rather than assuming:

```
https://api.unified.to/oauth/code          # us (default)
https://api-eu.unified.to/oauth/code       # eu
https://api-au.unified.to/oauth/code       # au
https://api-dev.unified.to/oauth/code      # dev
```

Notes:

- **All redirect URIs must be HTTPS**, except `localhost` URIs.
- Matching is exact — no subdirectory matching, no trailing-slash forgiveness, no wildcards. A mismatch fails at
  connect time, not at save time, so a bad entry survives review and breaks customers.
- The `redirect_uri` is technically *optional* for the code flow: with none, Dropbox shows the authorization code on
  screen for the user to copy. That is a manual-testing convenience, never a product flow.
- **Disable "Allow implicit grant"** unless something genuinely uses it. Leaving a legacy `response_type=token` flow
  enabled on a server-side app is free attack surface.
- The **Generated access token** button on the same tab mints a token for the owning account only. Useful for a smoke
  test; not an authorization mechanism.

## 5. Scopes — the Permissions tab

Scopes are enabled per app on the **Permissions** tab, and requested per authorization via the space-delimited `scope`
parameter on the authorize URL. The `scope` parameter can only request a **subset of what the Permissions tab has
enabled**; it cannot exceed it. Omit `scope` entirely and Dropbox requests everything enabled on the tab — which is
how an app ends up showing customers a consent screen far broader than it needs.

Each API endpoint documents its required scope. The ones a storage connector typically needs:

| Scope | Why |
| --- | --- |
| `account_info.read` | Read the authorizing account's profile (`/2/users/get_current_account`) |
| `files.metadata.read` | List and read file/folder metadata (`/2/files/list_folder`) |
| `files.content.read` | Download file contents |
| `files.metadata.write` | Write file properties and tags |
| `files.content.write` | Upload, create folders, move, delete |
| `sharing.read` | Read sharing settings and shared links |
| `openid` `profile` `email` | OIDC identity only — required for the `id_token`; `profile` for first/last name, `email` for email |
| `team_data.member` | Team apps only — required to use the Select-User / Select-Admin headers |

**Changing scopes after customers have authorized requires re-authorization.** A token carries the permission set it
was granted; enabling a new scope on the Permissions tab does **not** upgrade tokens already issued, and a refresh can
only return a subset of what was originally granted. Existing customers keep working with their old, narrower token
until they run the authorize flow again — at which point the missing calls start returning 401 with the required scope
named. If you widen the scope set, plan a re-authorization campaign, and look at `include_granted_scopes` (`user` or
`team`) so a re-auth adds to previously granted scopes instead of replacing them.

Ask for the least you need. Dropbox reviews scope breadth against actual functionality at production approval (§6),
and an over-broad consent screen costs conversions before it ever costs a review cycle.

### Product fact — Unified.to's Dropbox connector

**As of 2026-09-20, Unified.to's Dropbox connector requests:** `openid`, `profile` and `email` on every authorization,
plus — for reading files — `files.metadata.read`, `files.content.read` and `sharing.read`; for writing files —
`files.metadata.write`, `files.content.write` and `sharing.read`; and `account_info.read` for the account/employee
object. Scopes are space-delimited.

Also as of 2026-09-20, that connector: **appends `token_access_type=offline` to the authorize URL**, so it does
receive a refresh token; **does not use PKCE** for Dropbox, sending the app secret in the token request body
(`client_secret_post`, which Dropbox supports); authorizes at `https://www.dropbox.com/oauth2/authorize` and exchanges
at `https://api.dropboxapi.com/oauth2/token`; refreshes with `grant_type=refresh_token` plus the app key and secret;
and can run on Unified.to's **shared** Dropbox credentials rather than a customer-supplied app.

Two consequences worth raising before you create anything. That scope set reads pre-existing user content and sharing
state, which **App folder access cannot serve** (§3) — Full Dropbox is the likely correct choice, but confirm it.
And no team scope is in that list, so this is a **user app, not a Business/team app**. Confirm both, and the current
scope set, with the connector's owner before registering — this is a dated snapshot, not a contract.

## 6. Development vs production status

Every new app is created in **development** status. It works exactly like a production app; it just cannot link many
users. The numbers are specific, and the second one is the one that bites:

- **500 total linked users** is the development ceiling. Additional users beyond your own account are enabled from the
  app's page with **Enable additional users**.
- **At 50 linked users, a two-week clock starts.** You have two weeks to apply for *and receive* production approval.
  Miss it and the app's ability to link additional users is **frozen** — regardless of whether you are at 51 users or
  400.
- **A frozen app is only unfrozen by production approval.** Unlinking users does not help. Dropbox says this
  explicitly.
- **Dropbox will not review a production application until the app has linked at least 50 users**, unless you make a
  case in the **Request early review** field of the form. So the naive plan — apply early, be safe — does not work;
  you apply early and wait, or you make the early-review argument.

For a multi-tenant connector, treat 50 linked customers as a launch gate, and file the application (with the
early-review justification if the timeline demands it) well before you approach it.

**What the production application asks for**, from the app's page in the App Console via **Apply for Production**:

- How your app uses the API — be descriptive; Dropbox says explicitly that more detail means faster approval.
- An **app icon** (small and large), plus the Branding tab's publisher, description and app website.
- Adherence to the **developer branding guidelines** and the **developer terms and conditions** — the application is
  rejected outright if it does not comply. Notably: do not imply Dropbox endorsed, built or partnered on the app.
- A **privacy policy** specific to your app, describing what you do and do not do with user data.
- Scope and access-type justification: review checks that the app does not request a broader permission than its
  functionality warrants. If a broader permission is for planned-but-unbuilt functionality, **say so in the request**.

A denial comes with feedback and you can resubmit. **Once approved, the app name is frozen** — changing it afterwards
requires a support request.

Compliance attestations, legal claims, volume projections and security-questionnaire answers are business decisions.
**Do not invent them** — collect them from the user or hand back.

## 7. Capture the credentials

**App Console → your app → Settings tab.** The **App key** and **App secret** sit together; the secret is behind a
**Show** control. Dropbox calls them app key and app secret; the OAuth spec calls them `client_id` and
`client_secret`, and they are the same values.

Unlike some portals, **the app secret can be re-read later** from this page by anyone with access to the owning
account — which is convenient and also means account access equals credential access. Protect the owning account
accordingly.

Capture, for the handoff:

- **App key** (`client_id`) and **app secret** (`client_secret`)
- Authorize endpoint: `https://www.dropbox.com/oauth2/authorize`
- Token endpoint: `https://api.dropboxapi.com/oauth2/token`
- API base: `https://api.dropboxapi.com/` (content endpoints live on `https://content.dropboxapi.com/`)
- The **access type** (App folder or Full Dropbox) and, for App folder apps, the app folder name
- The exact **scope list** enabled on the Permissions tab
- Current **status** (development or production) and the linked-user count

Report the secret once so the user can paste it into their secret store, say plainly that it is now in the transcript
and can be regenerated, then move on.

Regenerating the app secret invalidates the old one. Existing access tokens keep working until they expire (about four
hours), but every token exchange and every refresh fails until the new secret is deployed — which for a connector with
stored refresh tokens means every customer breaks within hours, not gradually. Never regenerate without explicit
go-ahead and a cutover plan.

## 8. Token lifetimes and offline access

This is the failure that looks like success.

- Access tokens are **short-lived**. The documented token responses show `"expires_in": 14400` — four hours. Do not
  hardcode it; read `expires_in` from the response.
- `token_access_type` on the **authorize** URL controls what you get back, and it **defaults to `online`**:
  - `online` (default) → a short-lived access token, **and no refresh token at all**.
  - `offline` → a short-lived access token **plus** a long-lived `refresh_token`.
- The refresh token does not expire automatically and is reusable. (An optional
  `refresh_token_expiration_seconds` on the code exchange can give it an expiry; omit it for an indefinite token.)
- Refreshing: POST `https://api.dropboxapi.com/oauth2/token` with `grant_type=refresh_token`, the `refresh_token`, and
  the app key and secret. You get a new access token and a new expiry. The refresh token itself is not rotated.
- A user's approval stays valid until they revoke it from their Dropbox account's connected-apps settings. Revocation
  surfaces as a 401 — indistinguishable at the HTTP layer from an expired token, so handle both.

**The trap, precisely:** forget `token_access_type=offline` and nothing complains. Authorization succeeds, the token
response contains no `refresh_token`, and the connector works perfectly for one afternoon. Roughly four hours later
every call returns 401 and there is no way back without dragging the customer through the authorize flow again. If the
client is already deployed with `online`, fixing it is not a config change on the Dropbox side — **every affected
customer must re-authorize**, because the missing refresh token was never issued.

So before registering anything, confirm two separate things: that the client **sends `token_access_type=offline`**,
and that it **persists the `refresh_token`** from the exchange response. Either one missing produces the same symptom.

**PKCE** is available and recommended for clients that cannot keep the secret secure (desktop, mobile, single-page,
open-source). Send `code_challenge` and `code_challenge_method=S256` on authorize, and the `code_verifier` (43–128
characters from `[0-9a-zA-Z\-\.\_\~]`) on the exchange in place of the secret. A confidential server-side connector may
legitimately use the secret instead — but it is a choice to make knowingly, not by omission.

## 9. Verify end-to-end

Testing with the owning account proves less than it appears — it is already a linked development user, and the
Generated access token button bypasses the flow entirely. Test the path a customer takes.

1. Authorize from a **second Dropbox account** (enabled via **Enable additional users**) through your platform's real
   connect flow.
2. Inspect the raw token response: confirm a **`refresh_token`** is present, and note `expires_in` and the returned
   `scope` string. The `scope` string is the ground truth for what the token can do.
3. Make a read call against content the app should see. For a **Full Dropbox** app, list something the user created
   *before* installing the app — that is the check App folder access silently fails.
4. **Force a refresh** with `grant_type=refresh_token` and make the same call with the new access token.
5. If the account is a **Dropbox Business team**, repeat with the Select-User header and, for team-space teams, the
   Path-Root header.

| Symptom | Cause |
| --- | --- |
| No `refresh_token` in the token response | `token_access_type=offline` missing from the authorize URL (§8) |
| Works for ~4 hours, then every call 401s | Same — nothing to refresh with, token expired (§8) |
| Redirect fails before consent, or the URI is rejected | Redirect URI not registered exactly, or not HTTPS (§4) |
| Auth succeeds; user's existing files are invisible or the listing is nearly empty | App folder access type — cannot be changed, only replaced (§3) |
| 401 naming a required scope | Scope not enabled on Permissions, or the token predates it and needs re-authorization (§5) |
| Consent screen asks for far more than expected | `scope` parameter omitted, so all enabled scopes are requested (§5) |
| No `id_token` in the response | OIDC scopes not explicitly requested, or not using `response_type=code` (§5) |
| New users stop being able to link; existing ones fine | Development app frozen at the 50-user checkpoint (§6) |
| Team app cannot see team folders | Missing `Dropbox-API-Path-Root` on a team-space team (§3) |
| Team app 401s on a member call | Missing `team_data.member` scope, or a member ID not on the team (§3) |
| Every customer breaks within hours of a credential change | App secret regenerated without a cutover (§7) |

## 10. Hand off — never commit the secret

- **Do not** write the app secret into source control, a test, a fixture, a committed `.env`, a ticket, a PR body, or
  a chat channel. Values go to the user, for the secret store or console.
- If a code change is needed (a redirect host, a scope, `token_access_type=offline`), keep it secret-free and say what
  the human must set out of band.
- Close with: app name and owning account; **access type, and the fact that it is permanent**; app key; where the
  secret was delivered; authorize and token endpoints; the exact scope strings enabled; whether the client sends
  `token_access_type=offline` and stores the refresh token; current status (development or production), the linked-user
  count, and the plan for the 50-user checkpoint; and anything left for the user to do.

## Stop and ask

Hand back to a human rather than guessing when: the user cannot say confidently whether the connector needs **App
folder or Full Dropbox** (§3 — this is unrecoverable, and worth blocking on); the client does not send
`token_access_type=offline` or does not store the refresh token (report it — do not register and hope); the app needs
to serve both personal accounts and Dropbox Business teams; the fix requires deleting and recreating an app that
customers already use; regenerating the app secret is on the table; the production application asks for compliance,
legal, privacy-policy or volume claims; branding, naming or icons must be invented; a Business development account is
needed; or the App Console does not match the **Platform state** section above.

## References

- OAuth Guide — https://developers.dropbox.com/oauth-guide
- OAuth Guide (canonical) — https://docs.dropboxapi.com/dropbox-api/docs/oauth
- Authorization reference (`/oauth2/authorize`, `/oauth2/token`, `token_access_type`, PKCE) — https://docs.dropboxapi.com/dropbox-api/docs/get-started/authorization
- App Console tutorial (tabs, app key/secret, redirect URIs, access type is not editable) — https://docs.dropboxapi.com/dropbox-api/docs/get-started/tutorial/app-console
- DBX Platform developer guide (App folder vs Full Dropbox, production approval, 50/500 users) — https://docs.dropboxapi.com/dropbox-api/docs/developer-resources/developer-guide
- Developer branding guidelines — https://docs.dropboxapi.com/dropbox-api/docs/developer-resources/branding-guide
- Developer terms and conditions — https://www.dropbox.com/developers/reference/tos
- Authentication types (Select-User, Select-Admin, app auth) — https://docs.dropboxapi.com/dropbox-api/docs/auth-types
- Dropbox Business API overview (team apps, development teams, `team_data.member`) — https://docs.dropboxapi.com/dropbox-api/api-reference/business-endpoints/overview
- Team Files guide (namespaces, Path-Root, team space) — https://docs.dropboxapi.com/dropbox-api/docs/team-files
- OpenID Connect guide — https://developers.dropbox.com/oidc-guide
- Error handling (401/403 semantics, revocation) — https://docs.dropboxapi.com/dropbox-api/docs/error-handling
- OIDC discovery document — https://www.dropbox.com/.well-known/openid-configuration
- App Console — https://www.dropbox.com/developers/apps
- Create an app — https://www.dropbox.com/developers/apps/create
- Developer support / contact — https://www.dropbox.com/developers/contact
- Users revoking third-party app access — https://help.dropbox.com/installs-integrations/third-party/third-party-apps
- Team space overview — https://help.dropbox.com/organize/team-space-overview
