Decide who moves the bytes For small uploads, a Laravel server can accept a file, validate it, and store it through the S3 disk. For large files or high up...
Decide who moves the bytes
For small uploads, a Laravel server can accept a file, validate it, and store it through the S3 disk. For large files or high upload volume, a browser or mobile app can upload directly to S3 with a short lived presigned URL. The latter reduces load on the web server, but it moves some validation and completion checks into a separate workflow.
Neither option makes an uploaded object trusted. Decide the maximum size, allowed type, ownership, privacy, retention, and postprocessing before choosing the transfer path.
Server mediated uploads
Laravel's filesystem abstraction stores an UploadedFile on the configured disk and returns its object key. Validate the request first and generate a key controlled by the server. Persist that key, not a public URL that is difficult to migrate later. The disk's URL or a controlled download endpoint can produce an access URL when needed.
Keep AWS credentials scoped to the bucket and actions the application requires. A public marketing image and a private customer attachment should not share an unrestricted read policy.
Direct uploads with presigned URLs
The application authenticates the user, authorizes the target record, and creates a unique object key and a short lived URL limited to a specific upload operation. The client sends the file to S3, then calls the application to finalize. At finalization, verify the object exists, inspect size and type, and move it into a trusted state only after any required scanning or processing.
Amazon documents that a presigned URL can be reused until expiration and that uploading to an existing key replaces the object. Use unique keys and short expiry; do not assume "single use." Consider checksums and a staged prefix for unverified objects.
Avoid orphaned and untrusted objects
Clients can abandon uploads after requesting a URL. Record a pending upload with an expiry, then clean up old staged objects through a controlled job or bucket lifecycle rule. Do not expose staged objects to other users. When the finalization request arrives, verify that the pending record belongs to the authenticated user and intended business entity.
For image processing, store the original privately if needed and generate sized public derivatives after validation. Set the image dimensions in rendered markup to avoid layout shifts.
Test permission boundaries
Try finalizing another user's object key, replaying a presigned URL, uploading a different content type, exceeding the intended size, and requesting a download from another tenant. Test object storage failures independently from database failures. An upload record must not claim completion while the object is missing.
Conclusion
The architecture is a sequence of authorization, transfer, verification, and publication. Presigned URLs change where bytes travel; they do not remove the need for validation and access control. See cloud and DevOps solutions for infrastructure integration.
References