Skip to main content

Google Drive

This connector pins https://www.googleapis.com/drive/v3 and gives an agent the everyday half of Drive: searching for files, reading their metadata, seeing who they are shared with, pulling content down, and — once you switch them on — creating folders, copying, renaming, moving and deleting. It is the right connector for "find the Q3 deck and summarise it" or "put these into a new folder"; it cannot reach any other Google host.

What you need

Drive has no API keys. Access is OAuth only, so the connection is authorised by signing in to Google rather than by pasting a secret. You register your own Google OAuth app; your gateway runs the authorisation code flow against it and keeps the connection alive from there.

Needs gateway 1.1.0

From 1.1.0 the gateway performs the OAuth exchange itself, seals the tokens on your own machine, and refreshes the access token two minutes before it expires for as long as the connection exists. Older gateways have no OAuth endpoint at all. Check what you are running with curl -s http://127.0.0.1:7376/health and upgrade before you start.

Register a Google OAuth app

This setup is the same for all four Google connectors — Calendar, Meet and Gmail point back here. Do it once per Google Cloud project; each connector then only needs its own API enabled and its own scopes requested.

  1. Open the Google Cloud console, pick or create a project, and enable the Google Drive API under APIs & Services → Library.

  2. Configure the OAuth consent screen, and read the caution below before you leave the app in Testing.

  3. Under Credentials → Create credentials → OAuth client ID, choose Desktop app for a gateway on your own machine, or Web application for one reachable over a tunnel.

  4. Add the redirect URI, exactly as your gateway will send it:

    • 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.

    Google accepts a loopback address on a custom port for installed apps but requires HTTPS for web clients, so a tunnelled gateway must use its https:// host. A Web application client lists the URI under Authorized redirect URIs; a Desktop app client takes a loopback callback without one being listed.

  5. Note the client id and client secret. You hand both to your own gateway when you authorise the connection; neither ever reaches permaura.com.

An app left in Testing stops working every seven days

While your app's publishing status is Testing, a refresh token Google issues expires seven days from issuance, and refreshing it does not extend that — only a fresh consent resets the clock. It is Google's policy rather than a Permaura limit, so a connection built on a Testing app breaks weekly no matter how well the gateway behaves.

Three ways out:

  • Set the app's user type to Internal. Google Workspace organisations only, and it restricts the app to accounts in your own organisation, which is usually what you wanted anyway. Verification is not required and publishing status does not apply.
  • Publish the app to In production. Unverified is fine when you are the only user: you click through a "Google hasn't verified this app" screen once. Refresh tokens then persist, and Google only revokes one after six months without use.
  • Ask a Workspace admin to mark the app Trusted. That overrides both the 100-test-user cap and the seven-day expiry.

Ask for the least privilege that covers what you intend to enable:

ScopeGives you
https://www.googleapis.com/auth/drive.readonlyevery read action, across your whole Drive
https://www.googleapis.com/auth/drive.fileread and write, but only for files this app created or you explicitly opened with it

A read-only scope is the sensible default. drive.readonly covers listing, metadata, permissions, download and export, and cannot alter anything. If you want the write actions, prefer drive.file over the full drive scope: it limits the blast radius to files the connection itself touched, rather than handing over your entire Drive.

Add the connection

Both halves of this are gateway-side today. The console's Add connection dialog offers an OAuth path, but it reports itself as rolling out per provider, and the client id and secret it asks for go to permaura.com rather than to your gateway — which is the opposite of what you want here. So create the connection against the gateway with an operator token, 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": "google-drive",
"name": "drive-work"
}'

The response carries the connection_id you authorise below. Creating the connection makes the actions possible, not permitted — an agent still needs a grant.

Authorise it

Ask the gateway for an authorisation link, passing the client id and secret from the app you registered:

curl -s -X POST $BASE/v1/connections/<connection_id>/oauth/start \
-H "authorization: Bearer $TOKEN" -H 'content-type: application/json' -d '{
"client_id": "<your-client-id>",
"client_secret": "<your-client-secret>",
"redirect_uri": "http://127.0.0.1:7376/oauth/callback",
"scopes": ["https://www.googleapis.com/auth/drive.readonly"]
}'

The response carries an authorize_url. Open it in a browser and approve. Google redirects back to your gateway, which exchanges the code itself, seals the access token, refresh token and client secret as the connection's credential, and shows a plain Connected page. The credential is encrypted on your gateway, injected server-side on every approved call, and never readable again. From then on the gateway refreshes the access token on its own, two minutes before expiry, on the invoke path — there is nothing to re-paste and nothing to rotate.

permaura.com is never part of that exchange and never sees any of it. The tokens exist on your gateway and nowhere else.

Four things worth knowing before you run it:

  • redirect_uri must match what you registered with Google, character for character. It is a required field rather than something the gateway infers, because a mismatch is the most common way this fails. Loopback (http://127.0.0.1:7376/oauth/callback, or the localhost form) may be plain http; anything else must be https.
  • scopes is optional — omit it to use the manifest's own set. PKCE is added automatically, because the connector's manifest records that Google supports it.
  • The authorize link is single-use and expires after 10 minutes. If you are slower than that, start again.
  • If Google returns no refresh token, the gateway refuses the exchange rather than sealing a credential that would die within the hour, and says so. Permaura asks for access_type=offline&prompt=consent precisely so that Google issues one.
Run this from the gateway's own host if you have a device enrolled for approvals

Sealing a credential changes the upstream identity a connection acts as, so it counts as a mutation held for a device signature — and a browser redirect cannot carry an approval. With a device enrolled, starting the flow over a tunnel or the permaura.com broker is refused. Run it locally on the machine the gateway is on.

What the agent can do

ActionWhat it doesOn by default
files.listLists or searches files with a Drive queryYes
files.getReads a file's metadataYes
files.downloadDownloads a binary file's contentYes
files.exportExports a Docs, Sheets or Slides file to another formatNo
permissions.listLists who a file is shared withYes
folders.createCreates a folderNo
files.copyCopies a fileNo
files.updateUpdates metadata, or moves a file between foldersNo
files.deletePermanently deletes a file, bypassing the trashNo — and asks a human every time

files.export is a read, but the risk classifier treats an export as data egress and starts it switched off along with the writes. Be aware of the asymmetry that leaves behind: files.download pulls the same bytes and is on by default. If you want the agent reading metadata but never file contents, switch files.download off yourself on the connection's capability list — it will not do that for you.

Good to know

  • Download and export are different endpoints. files.download is GET /files/{fileId} with alt=media and works only for files stored as bytes — PDFs, images, uploaded Office documents. Google-native files (Docs, Sheets, Slides) have no bytes to fetch and return an error; use files.export with a mimeType such as application/pdf or text/csv instead. Exports are capped at 10 MB, so a very large document has to be fetched another way.
  • folders.create is files.create in disguise. There is no folders endpoint in Drive: a folder is a file whose mimeType is application/vnd.google-apps.folder. The action posts to /files with that MIME type, a name, and optionally a parents array.
  • Moving a file is files.update with the addParents and removeParents query parameters, not a body field.
  • files.delete skips the trash. It is permanent and unrecoverable, which is why it is critical and approval-gated. If you want the recoverable version, use files.update with trashed: true instead.
  • Shared drives. Files on a shared drive are invisible unless the call passes supportsAllDrives=true, and files.list also needs includeItemsFromAllDrives=true. Both are forwarded by this connector; the agent has to set them.
  • Search syntax. files.list takes a q in Drive's own query language, for example name contains 'report' and mimeType = 'application/pdf' and trashed = false.
  • Quotas. Drive bills in quota units per minute — 1,000,000 per project and 325,000 per user, where a list costs 100 units, a download 200, an edit 50 and a metadata read 5. Downloads are the expensive ones.
  • Email addresses and profile photo links are redacted from responses by default, which mostly affects permissions.list and file owner fields. Turn that off on the connection only if the agent genuinely needs them.