Uploading objects to AWS S3 with presigned URLs
19/05/2025
99
Table of Contents
I’m Quang Tran, a full-stack developer with four years of experience. I’ve had my fair share of struggles when it comes to uploading files to cloud storage services like Amazon S3. Not too long ago, I used to rely on the traditional method: the server would receive the file from the client, store it temporarily, and then push it to S3. What seemed like a simple task quickly became a resource-draining nightmare, and my server started to “cry out” from the overload.
But then, I discovered Presigned URLs—the technique that allows clients to upload files directly to S3 without burdening the server. Presigned URLs help us solve the issues mentioned above. Today, I will show you how to implement this in SupremeTech‘s article.
Traditional file uploading
When you use applications with file upload features, such as uploading photos to social media platforms, the process is mainly done by selecting a photo from your device and sending it to the server for storage. This process started with traditional upload and has evolved over time. The steps were as follows:
- The user selects a photo from the device.
- The client sends a request to upload the photo to the server.
- The server receives and processes the photo, then stores it in the storage.

This process may seem simple, but it can impact the server’s performance. Imagine when thousands of people are uploading data at the same time, and the data size is large; your server could become overloaded. This requires you to scale your application server and ensure available network bandwidth.
After identifying this issue, AWS introduced the Presigned URL feature as a solution. So, what is a Presigned URL?
What is the Presigned URL?
A presigned URL is a URL that you can provide to your users to grant temporary access to a specific S3 object. You can use a presigned URL to read or upload an object to S3 directly without passing it through the server. This allows an upload without requiring another party to have AWS security credentials or permissions. If an object with the same key already exists in the bucket specified in the presigned URL, Amazon S3 replaces the existing object with the uploaded object.
When creating a presigned URL, you must provide the following information:
- Amazon S3 bucket name
- An object key (if reading this object will be in your Amazon S3 bucket, if uploading, this is the file name to be uploaded)
- An HTTP method (GET for reading objects or PUT for uploading)
- An expiration time interval
- AWS credentials (AWS access key ID, AWS secret key ID)
You can use the presigned URL multiple times, up to the expiration date and time.
Amazon S3 grants access to the object through a pre-signed URL, which can only be generated by the bucket’s owner or anyone with valid security credentials.
How to upload a file to S3 using a presigned URL?

How to create a presigned URL for uploading an object?
We already know what a presigned URL is, so let’s explore how to create one and upload a photo through it.
There are two ways to create a presigned URL for uploading, which are:
- Using the AWS Toolkit for Visual Studio (Windows).
- Using the AWS SDKs to generate a PUT presigned URL for uploading a file.
In this blog, I will introduce how to use the AWS JS SDK (AWS SDK for JavaScript) to generate a PUT presigned URL for uploading a file.
Using the AWS JS SDK
First, you need to log in to the AWS console with an account with permission to read and write objects to S3.
- When you use the AWS SDKs to generate a presigned URL, the maximum expiration time is 7 days from the creation date.
- You need to prepare the AWS credentials (AWS access key ID, AWS secret key ID), region, S3 bucket name, and object key before uploading and securely storing them on the server.
Before we start creating a presigned URL, there are a few important things to note as follows:
- Block all public access to the S3 bucket (crucial for data security, preventing accidental data leaks or unauthorized access to sensitive information)
- Never store AWS credentials in front-end code (access key ID, secret key ID)
- Use environment variables and secret managers to store AWS credentials securely
- Limit IAM permissions (least privilege principle – AWS recommendation)
- Configure CORS to allow other origins to send file upload requests
To create a direct image upload flow to S3, follow these steps:
- On the front-end, you call the API to create a presigned URL on the back-end server and send the key of the object you want to store.
- On the back end, you create an API to generate the pre-signed URL, as shown below, and respond to the front-end.
import { PutObjectCommand, S3Client, } from '@aws-sdk/client-s3'; import { getSignedUrl } from '@aws-sdk/s3-request-presigner'; const createPresignedUrlWithClient = async ({ region, bucket, key }) => { const client = new S3Client({ region, credentials: { accessKeyId: 'your access key id', secretAccessKey: 'your secret key id', }, }); const command = new PutObjectCommand({ Bucket: bucket, Key: key }); return await getSignedUrl(client, command, { expiresIn: 36000 }); }; const presignedUrl = await createPresignedUrlWithClient({ region: 'ap-southeast-1', bucket: 'your-bucket-name', key: 'example.txt', });
- The front-end receives the response and performs a PUT request to upload the file directly to the S3 bucket.
<!-- wp:table --> <figure class="wp-block-table"><table><tbody><tr><td><strong>const</strong> putToPresignedUrl = (presignedUrl) => {<br> <strong>const</strong> data = 'Hello World!';<br> axios.put(presignedUrl, data);<br>};</td></tr></tbody></table></figure> <!-- /wp:table -->


An example of a presigned URL:
https://presignedurldemo.s3.ap-southeast-1.amazonaws.com/example.txt?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAUPMYNICO4HMDKONH%2F20250101%2Fap-southeast-1%2Fs3%2Faws4_request&X-Amz-Date=20250101T021742Z&X-Amz-Expires=36000&X-Amz-Signature=9f29f0f34a19c9e9748eb2fc197138d4345e0124746f99ad56e27e08886fa01a&X-Amz-SignedHeaders=host&x-amz-checksum-crc32=AAAAAA%3D%3D&x-amz-sdk-checksum-algorithm=CRC32&x-id=PutObject
Among them, there are query parameters that are required for S3 to determine whether the upload operation is allowed.
Query parameter | Description |
X-Amz-Algorithm | The signing algorithm used. Typically AWS4-HMAC-SHA256 |
X-Amz-Credential | A string that includes the access key ID and the scope of the request. Format: <AccessKey>/<Date>/<Region>/s3/aws4_request. It helps AWS identify the credentials used to sign the request. |
X-Amz-Date | The timestamp (in UTC) when the URL was generated. Format: YYYYMMDD’T’HHMMSS’Z’. |
X-Amz-Expires | The number of seconds before the URL expires (e.g., 3600 for one hour). After this time, the URL becomes invalid. |
X-Amz-SignedHeaders | A list of headers that are included in the signature. Commonly just host, but can include content-type, etc., if specified during signing. |
X-Amz-Signature | The actual cryptographic signature ensures that the request has not been tampered with and proves that the sender has valid credentials. |
Now that you know how to generate a presigned URL, let’s examine some limitations you should consider.
Limitations of Using S3 Presigned URLs
- 5GB Upload Limit: 5GB per-request upload limit in S3, with no easy way to increase it
- URL Management Overhead: A unique URL must be generated for every upload, increasing code complexity and backend logic.
- Risk of Unintended Access: Anyone with the URL can upload until it expires. There’s no built-in user validation.
- Client-Side Upload Issues: Client-side uploads can cause data inconsistency if an error occurs mid-upload.
See more:
- Mastering AWS Lambda: An Introduction to Serverless Computing
- AWS Lambda Triggers: How to Trigger a Lambda Function?
- Best Practices for Building Reliable AWS Lambda Functions
Conclusion
You have learned another way to upload objects to S3 directly without requiring public access to your S3 bucket. Please choose the method that best fits your use case.
References:
AWS (no date) Uploading objects – Amazon Simple Storage Service, AWS. Available at: https://docs.aws.amazon.com/AmazonS3/latest/userguide/upload-objects.html (Accessed: 19 May 2025).
AWS (no date b) Uploading objects with presigned URLs – Amazon Simple Storage Service, AWS. Available at: https://docs.aws.amazon.com/AmazonS3/latest/userguide/PresignedUrlUploadObject.html (Accessed: 19 May 2025).
Related Blog