Skip to main content

Dropbox

The Dropbox connector reaches https://api.dropboxapi.com/2, the RPC half of the Dropbox API v2, for one Dropbox account. It is good for finding things and reporting on them: list a folder, search by name, read a file's metadata and revision history, see what has been shared. It can also create folders, move files, publish shared links and delete, but those four ship switched off, and the two that are hardest to take back need an approval.

What you need

A Dropbox app that you register yourself, and its app key and app secret.

1. Create the app. Go to the App Console and choose Create app. Pick Scoped access, then choose the access type:

  • App folder is the least-privilege option. Your app only ever sees its own folder under /Apps, and nothing an agent does can touch the rest of your Dropbox. Prefer this.
  • Full Dropbox sees everything in the account. Only pick it if the files you need already live elsewhere in the account.

2. Set the permissions before you connect. On the app's Permissions tab, tick only what you will actually enable:

ScopeNeeded for
account_info.readaccount.read
files.metadata.readlisting, searching, metadata, revisions
files.content.readfiles.get_temporary_link
files.content.writefiles.create_folder, files.move, files.delete
sharing.readsharing.list_shared_links
sharing.writesharing.create_shared_link

Click Submit on that tab. Scopes are baked into a token when it is issued, so a credential sealed before you ticked a box will not gain it later. Change the permissions first, then run the flow.

3. Note the app key and app secret, and register the redirect URI. All three live on the app's Settings tab. The App key is your OAuth client id and the App secret your client secret. Under Redirect URIs, add http://127.0.0.1:7376/oauth/callback for a gateway running on your own machine, or https://<your-gateway-host>/oauth/callback for a tunnelled gateway. Dropbox rejects any redirect that is not registered here, exactly.

The same tab has a Generate button for an access token tied to your own account. It is a quick way to smoke-test the connector, but it is short-lived and there is nothing behind it to renew it. The flow below is the one that lasts.

OAuth runs on the gateway, not in the console

Gateway 1.1.0 and later runs the whole authorisation code flow itself, against the app you just registered. A scoped Dropbox app issues a short-lived access token together with a refresh token; the gateway seals both, and the client secret, as the connection's credential, and from then on refreshes the access token on its own two minutes before it expires, on the invoke path. Nothing to re-paste, nothing to babysit. permaura.com is never involved and never sees any of it.

What is not there yet is a Sign in with Dropbox button: permaura.com's connector OAuth endpoint still answers with a "rolling out" response. Today you start the flow through the gateway's own REST API, as below.

Add the connection

Both halves of this are gateway-side today. The console's Add connection dialog will not create a connection without a credential, and the OAuth path it offers sends your client id and secret to permaura.com rather than to your gateway — the opposite of what you want here. So create the connection against the gateway, and authorise it there too:

BASE=http://127.0.0.1:7376
curl -s -X POST $BASE/v1/connections/from-preset \
-H "authorization: Bearer $TOKEN" -H 'content-type: application/json' -d '{
"preset_id": "dropbox",
"name": "dropbox-work"
}'

The response carries the connection_id used below. Then start the flow with an operator token:

curl -s -X POST $BASE/v1/connections/$CONNECTION_ID/oauth/start \
-H "authorization: Bearer $TOKEN" \
-H 'content-type: application/json' -d '{
"client_id": "…your app key…",
"client_secret": "…your app secret…",
"redirect_uri": "http://127.0.0.1:7376/oauth/callback"
}'

The response carries an authorize_url. Open it in a browser and approve. Dropbox redirects back to your gateway, which finishes the exchange and shows a plain "Connected" page. The credential is sealed on your gateway and never displayed again. Nothing can use it until a grant allows it.

A few things to watch:

  • redirect_uri has to match what you registered with Dropbox, exactly. The gateway asks for it rather than guessing, because a mismatch is the most common way this fails. Loopback addresses (http://127.0.0.1:7376/oauth/callback, http://localhost:…) may be plain http; anything else has to be https.
  • PKCE is automatic. The gateway applies it where the connector's manifest records that the provider supports it, which Dropbox does. You still pass the app secret.
  • Ask for the scopes you actually ticked. Leave scopes out and the gateway requests every scope the connector's manifest declares — all six in the table above. If you enabled a subset on the Permissions tab, pass that subset instead, so the authorisation asks for exactly what the app can grant.
  • The authorize link is single-use and expires after ten minutes. Start again if it goes stale.
  • No refresh token, no credential. If Dropbox comes back with an access token and no refresh token, the gateway refuses the exchange rather than sealing something that expires in a few hours, and the error says so.
  • Run it from the gateway's own host if you have a device enrolled for approvals. Sealing a credential changes the upstream identity the connection acts as, so it is held for a device signature, and a browser redirect cannot carry one. Starting the flow over a tunnel or the broker is refused in that setup.

What the agent can do

ActionWhat it doesOn by default
files.list_folderLists the contents of a folderYes
files.list_folder_continueFetches the next page of a folder listingYes
files.searchSearches for files and folders by nameYes
files.get_metadataReads the metadata of one file or folderYes
files.get_temporary_linkMints a four-hour direct link to a file's contentsYes
files.list_revisionsLists the revisions of a fileYes
sharing.list_shared_linksLists existing shared linksYes
account.readReads the account the token belongs toYes
files.create_folderCreates a folderNo
files.moveMoves or renames a file or folderNo
sharing.create_shared_linkPublishes a shared link to a file or folderNo, and needs approval
files.deleteDeletes a file or folderNo, and needs approval

Good to know

  • File contents are not included, by design. Dropbox splits its API across two hosts. Metadata and search live on api.dropboxapi.com; upload, download, export, thumbnails and previews live on content.dropboxapi.com and take their arguments in a Dropbox-API-Arg header rather than a JSON body. The connector's base URL pins one host, which is what stops an agent redirecting a call somewhere else, so the content host is out of reach and those operations are deliberately left out. files.get_temporary_link is the way across: it runs on the API host and returns a URL that streams the file for four hours, after which it returns 410 Gone. Treat that URL as sensitive; anyone holding it can read the file.
  • Reads are POSTs here, and that is fine. Almost every Dropbox endpoint is a POST with a JSON body, including pure lookups. Left alone, Permaura's classifier would call all of them writes and switch them all off. The manifest overrides the eight genuine reads to read, list or search at medium risk so the connector is useful the moment you connect it. The four real writes keep their high or critical rating.
  • account.read takes no arguments, and that is the point. Dropbox wants no body at all on its no-argument routes, and that is exactly what the gateway sends when a capability declares no parameters. It is the quickest way to check a token works. The same rule cuts the other way for sharing.list_shared_links, whose three parameters are all optional: the gateway leaves the request body off entirely unless the agent supplies at least one of them, and Dropbox expects JSON on that route. Have the agent pass something; direct_only will do.
  • The root folder is an empty string, not /. files.list_folder with path: "" lists the top of the app folder or the account. path: "/" is rejected. Everything below it is a normal absolute path, such as /Reports/q3.pdf, and is case-insensitive but case-preserving.
  • Deleting is recoverable, publishing is not. files.delete moves an item to the Dropbox trash, where it can be restored for a window that depends on your plan. sharing.create_shared_link hands out a URL, and on some plans that URL is viewable by anyone who has it. Both are approval-gated; the shared link is the one to think hardest about.
  • Rate limits are dynamic. Dropbox does not publish a fixed number. When you go too fast you get a 429 with a Retry-After header saying how many seconds to wait. Agents that page through a large folder with files.list_folder_continue are the usual cause.
  • Account details are redacted. Email address, the name fields, profile photo URL, account and team member ids are stripped from responses before the agent sees them, so account.read confirms the connection works without handing over the account holder's identity.