I have a solution to this that is suitable to both S3 and DigitalOcean spaces (as well as any other provider that uses S3 style object storage).
Firstly, as has been established here, and in this post (Strapi.service outside api?), strapi does not use it’s own service functions when creating a new content. This is legitimately buckwild to me because of how opinionated the architecture is but there you go.
- Integrate S3/DO upload as normal. This is going to upload your files, as normal to you object storage service, and store them publicly.
- Webhook onto the creation of the content, ideally onto entry.create. Here you can create an S3 client instance, hop onto your S3 and change the previously uploaded public ACL to private.
- Update your service.find function (and similar) to intercept, and change the existing URL (which is private) to a SignedUrl (which can be made public for up to 7 days).
The major flaw in this approach is that by making the file private on creation you exclude the editor from accessing it. Technically the file’s hash and extension still compose to a valid object in the bucket, but you’d need to implement custom logic to essentially presign URLs every time the editor edits it.
Now in some cases this is fine. A CMS user will chuck in a file/video whatever, and only ever access it through the public CMS API which will, based on this logic, always deliver a fresh Pre-signed URL to the content, but if your CMS user frequently checks the content via the editor, then you’ll need to override the editors endpoints as well.
I haven’t done this because it’s not really in scope of what I’m doing.
…Of course a simple fix would be if Strapi used the services it makes us implement