How to send private Bubble files to OpenAI, OCR, e-signature, and PDF services securely

The short answer
Do not give an external processor a Bubble admin token, and do not make a private file public so the processor can fetch it. Put a small server-side relay between Bubble and the external service. The relay authorizes the current Bubble user and file record, downloads the file with a server-held Bubble credential, and uploads the bytes to the approved processor using that processor's credential. Neither credential reaches the browser or the other provider.
This directly addresses a recurring Bubble Forum problem: builders need to send private files to AI, translation, e-signature, OCR, or PDF services, but the remote service cannot fetch the protected Bubble URL. Suggested workarounds often involve query-string API tokens, temporary public copies, or plugins with size and filename limitations. See the discussions about posting a private file through an API and external access to private files.
First, make the Bubble file genuinely private
Bubble's file security documentation distinguishes hiding the database field that contains a file URL from protecting the file itself. Hiding the field only prevents an unauthorized user from discovering the URL through normal data access. The file remains readable if someone obtains that URL. The privacy rule's View attached files permission protects the file request itself.
For a tenant-aware application, attach the file to a record that has a stable organization ID. The authorization decision should answer all of these questions before bytes move:
Who is the authenticated Bubble user?
Which organization owns the file record?
May this user run this specific processing action?
Is the file active, within the allowed size, and an accepted media type?
Is the destination processor allowlisted for this action?
Do not accept a tenant ID, Bubble file URL, or destination URL from the browser and trust it directly. Send a stable application file ID and a named operation such as extract_invoice_text. Resolve the file and destination from trusted server-side data.
The relay flow
A working request sequence is:
Bubble creates a processing job with
status = requestedand a unique job ID.Bubble calls a private integration endpoint with the job ID and file record ID.
The integration service authenticates Bubble and loads the trusted file record.
It checks the actor, tenant, job type, file state, and destination policy.
It fetches the private Bubble file with a server-held bearer credential.
It uploads the bytes to the processor using a separate provider credential.
It stores only the provider's bounded job or file identifier—not either credential.
It returns quickly or records
submittedwhile asynchronous processing continues.A callback or polling worker verifies completion and updates the Bubble job.
Bubble documents bearer authentication for incoming API requests in How to authenticate. Keep that credential in the relay's secret store. Do not append it to the file URL: URLs are routinely captured in logs, histories, analytics, and support screenshots.
A tested byte-preserving relay
The repository includes a locally tested reference function at forum-operations-reference.mjs. Its essential shape is:
The automated test proves that the relay preserves byte content, media type, and filename; sends the Bubble token only to the Bubble source; and sends the processor token only to the destination. The destination request will differ by provider—some use multipart form data, some provide an upload URL, and others accept a raw request body—but the credential boundary remains the same.
For large files, stream the response rather than buffering it entirely. Enforce a maximum declared size and a maximum observed byte count. Abort both requests when the limit is exceeded. A Cloud Run relay should also use explicit request deadlines and memory settings appropriate to the tested file range.
When Cloud Storage is the better handoff
If the processor can fetch a URL but cannot accept an authenticated upload, the relay can copy the approved file into private Google Cloud Storage and issue a short-lived signed GET URL for one object. Google documents that anyone possessing a signed URL can use it until expiry. Treat it as a temporary bearer credential:
use one object and one method;
use the shortest duration compatible with the processor;
send it only to the intended provider;
never store it as the durable Bubble file URL;
record issuance without logging the query string;
delete or lifecycle-manage the temporary object.
This pattern is useful when a provider insists on pulling the file. A direct relay is preferable when the provider accepts a server upload because it avoids placing a reusable URL in another system.
Preserve the filename without trusting it
Processors often infer file type or display name from the final URL segment. Signed storage URLs can obscure that name, while user-supplied filenames may contain unsafe characters. Keep three values separate:
an opaque storage object name;
a sanitized display filename;
a verified or policy-approved content type.
Send the sanitized filename through the provider's supported metadata field. Do not use it as the storage authorization key. A file called invoice.pdf is not proven to be a PDF; inspect its bytes or pass it through the application's validation process before enabling file-type-specific processing.
Failure and cleanup rules
The job record should distinguish requested, fetching, uploading, submitted, completed, failed, and expired. Save a sanitized error class such as source_denied, size_rejected, or processor_timeout. Do not save response bodies that may contain credentials or extracted customer content.
Make submission idempotent. If Bubble repeats the same job request, return the existing provider job ID rather than uploading the file twice. If the destination result is uncertain, reconcile with the provider before retrying. Delete temporary copies only after the processor no longer needs them, and record whether cleanup succeeded.
Verification checklist
A user from tenant B cannot submit tenant A's file ID.
A browser cannot retrieve either provider credential.
The processor never receives the Bubble bearer token.
The Bubble source never receives the processor token.
A disallowed destination URL is rejected.
Oversized and unexpected file types fail before expensive processing where possible.
The relay preserves exact bytes, content type, and sanitized filename.
Repeating the same job does not create a second provider upload.
Logs contain job IDs and outcomes, not tokens, signed URLs, or file bodies.
Temporary objects and expired jobs have an explicit cleanup path.
The reference relay test passed locally on 2026-10-02. A publication-ready tutorial still needs one real provider adapter and a disposable Bubble app acceptance test.
For the download authorization decision behind this pattern, see Private Cloud Storage downloads for Bubble. For file threat modeling, use the Bubble file-upload security checklist.
Primary CTA: Tell us which private-file processor your Bubble workflow needs to reach.
Sources checked: Bubble Files, Privacy rules, API authentication, and Google Cloud signed URLs, checked 2026-10-02.
