Read this first
Google Drive delivery works, but two current limitations decide how you must configure it.What Drive delivery is, and is not
Tornado authenticates to Drive as a Google service account using a signed JWT, the same credential type as Google Cloud Storage. There is no OAuth consent screen and no “sign in with Google” redirect. You create the service account, you share a folder with it, you paste its JSON key. The backend requests exactly one scope:drive.file under non-sensitive scopes and marks it Recommended. It grants
the ability to “Create new Drive files, or modify existing files, that you open with an app
or that the user shares with an app while using the Google Picker API or the app’s file
picker”. In practice, for a server-side service account with no file picker, that means
Tornado sees only the files Tornado itself created.
If you point Tornado at a folder that already contains 500 files, Tornado cannot list,
read, overwrite or delete any of them. It can only add new files alongside them, and
manage those. This is a deliberate least-privilege choice, and it is also why Tornado
can never be used to exfiltrate the rest of your Drive.
The step everyone misses: share the folder with the service account
A service account is a Google identity with its own email address. It is not you, it cannot see your Drive, and it is not a member of your organisation unless you add it. Sharing the destination folder with that email address is not optional. Skip it and you land in one of two failure modes:- You set a
folder_idthe service account cannot see. Drive does not distinguish “not shared with you” from “does not exist”, so every upload fails with a 404 on a folder that is plainly sitting in your browser. - You left
folder_idempty, so Tornado targets the service account’s own root Drive. That Drive belongs to a robot identity with no web UI you can log into, and it has no storage quota, so uploads fail withstorageQuotaExceededagainst a destination you cannot inspect.
Finding the service account’s email address
It is theclient_email field inside the JSON key file you downloaded. It always ends in
.iam.gserviceaccount.com:
Minimum and recommended access
Drive has no policy document. What you grant is one OAuth scope plus one sharing level, and Tornado picks the scope for you, so the only decision you make is the sharing level.Minimum
Those cover everything Tornado calls:
files.create (the resumable upload and its chunks),
files.list (finding a delivered file by name, and the one-item validation call), and
files.delete.
Recommended
The minimum sharing level is the recommendation. Content manager is already the lowest role that works, and Manager adds only member management and the ability to delete the shared drive itself, neither of which Tornado touches. One thing about placement is worth a line:Storage quota: use a Shared Drive, not My Drive
This is the single most important decision on this page, and the answer differs between My Drive and Shared Drives. Google’s Drive API documentation states it plainly:Service accounts don’t have storage quota and can’t own any files. Instead, they must upload files and folders into shared drives, or use OAuth 2.0 to upload items on behalf of a human user.Combine that with the ordinary Drive storage rule, “Only the files you own count toward your Google storage”, and the consequence follows:
Google Workspace caps uploads at 750 GB per day per user across My Drive and all shared
drives. High-volume delivery can hit this. Nothing on the Tornado side raises it.
Setup
1. Create a Google Cloud project and enable the Drive API
1
Create the project
Go to console.cloud.google.com/projectcreate,
or in the Cloud console open Menu > IAM & Admin > Create a Project.Enter a project name, optionally edit the project ID (it cannot be changed later), pick
a location, then click Create.An existing project is fine. The project only carries the service account and the API
enablement, it has nothing to do with where the files land.
2
Enable the Drive API
In the Cloud console go to Menu > APIs & Services > Library > Google Workspace,
click Google Drive API, then click Enable.Direct link: console.cloud.google.com/apis/library/drive.googleapis.comOr with the CLI:Skipping this step produces a 403 with
accessNotConfigured on the first upload, not
at configuration time.2. Create a service account and download its JSON key
1
Create the service account
Go to console.cloud.google.com/iam-admin/serviceaccounts,
select your project, click Create service account, enter a name such as
tornado-drive, then click Done.Assign no IAM roles. Cloud IAM roles do not grant Drive access. Drive permissions come
exclusively from Drive sharing, which is step 3.2
Create a JSON key
Click the service account’s email address, open the Keys tab, then
Add key > Create new key, select JSON, and click Create. The file
downloads automatically.Google notes that “This file is the only copy of this key. After you download the key
file, you cannot download it again.”
3
Note the client_email
3. Share the destination folder with the service account
- My Drive folder
4. Find the folder ID
Open the folder in Drive and read it out of the address bar. The ID is everything after/folders/:
/drive/folders/ is the shared
drive’s own ID, which is a valid parents value.
5. Configure Tornado
Storage is resolved per API key. A configuration set on one key does not apply to your other keys. Run this for every key you send jobs with.Field reference
Characters rejected in
folder_prefix:
Through the dashboard
The dashboard’s Drive tile is blocked by limitation 1 above, so this is recorded for completeness rather than as a working path. The wire format nests the config under the provider key:service_account_json and Destination folder ID to folder_id.
service_account_json is capped at 10,000 characters on this route. A standard Google key
file is roughly 2.3 KB, so this only bites if you paste something other than the key.
What “verified” actually proves
POST /user/gdrive validates the credentials live before saving, and the dashboard button
says Connect & verify. Be precise about what that check covers.
The validation mints an OAuth token from the JSON key, then issues a one-item
files.list. That proves the service account exists, the private key parses and signs,
the Drive API is enabled on the project, and the drive.file scope is granted.
It does not touch folder_id. The list call carries no folder filter, and under
drive.file a fresh service account has created nothing, so it returns an empty list and
the check passes.
Nothing is written. The dashboard’s S3 probe was extended to write, read back, open and
abort a multipart upload, and delete; Drive validation is a single read-only files.list
and was not changed. If you have read the AWS S3 page, do not carry over
what it says about the probe.
Troubleshooting
The job says Completed but nothing appears in my folder
Work through these in order.
1
Check which API key sent the job
Storage is per key. If the job went out on a key with no Drive config, the file went to
Tornado’s managed storage and the job still reports
Completed. This is the most
common cause. Re-run POST /user/gdrive with the x-api-key you actually send jobs
with.2
Check that folder_id was not empty
An empty or omitted
folder_id sends everything to the service account’s own root
Drive, which no human can browse. There is no read-back endpoint for Drive
configuration, so if you are unsure, simply re-run POST /user/gdrive with the correct
folder_id. It overwrites the previous config for that key.3
Check the file name, not the folder tree
Drive does not create nested folders. If you set
base_folder or folder_prefix, look
for a flat file literally named videos/my-video.mp4 inside the destination folder,
not for a videos subfolder.4
Check that you are looking at the right Drive
A shared drive and a My Drive folder can have the same name. Confirm the ID in the URL
matches the
folder_id you configured.Permission and lookup errors
Quota errors
Download link problems
Thes3_url returned for a Drive delivery is a permanent
https://drive.google.com/file/d/{id}/view link, not a presigned URL. It does not expire,
and anyone opening it needs Drive permission on that file. Sharing the link with someone
outside the folder’s access list will show them a request-access page.
Tornado resolves that link by looking the file up by name inside the folder. Two jobs
that produce identical file names will collide, and the lookup returns whichever one Drive
answers with first. The same applies to DELETE. If that is a risk for you, set a distinct
per-job folder value on POST /jobs, which is folded into the file name and keeps the
names unique.
Removing the configuration
DELETE.
Related
Custom Storage
S3, Azure Blob, GCS and Alibaba OSS configuration
POST /user/gdrive
Full endpoint reference
