Upload (access)image (or video or any content) to S3 via pre-signed Url with NodeJs

Tony Nguyen
4 min readMar 31, 2021
Sending image to private s3 bucket from FE using signed url

Signed url is a url, which is generated by an authorised account. Anyone has the signed url can use it at any time and many times as they need as long as the url hasn’t expired.

Why should we use signed url?
Uploading heavy content from S3 via your own server consumes its resources and your front-end might need to wait longer for images being uploaded to AWS S3, you pass that job to AWS by using signed url.

Any drawbacks?
As the definition above “Anyone has the signed url can use it at any time and many times as they need as long as the url hasn’t expired.”. Anyone has the url can access your content is not what you want for sure. But we can use AWS S3’s policies and permission to minimise this soon.

Let’s hand on how to generate and use a signed url

  1. Create a S3 bucket
  2. Create a NodeJs server serving 2 apis signed-url-upload (for uploading image) and signed-url-access (for accessing image)
  3. Using Postman to test apis and signed url

1. Create a S3 bucket

  • If you don’t have AWS account yet. Follow this to create one
  • Then create an S3 bucket by following those step.
  • We also need AWS access key and secret key when generating signed url, following this to create one pair if you don’t have yet

Note: Keep block all checked to keep your bucket private.

Create S3 bucket

You might need to setup CORs for your S3 bucket:

Set up CORS

2. Create a NodeJs server

Create NodeJs express server using type script.

Create first signed-url-upload endpoint

Code explain

  • You can pass fileName, extension and mediaType the name and extension that you want for the content when it store in S3 and the type corresponding to that content, I used "demo-image.png” as default then mediaType must be image.
  • Bucket is name of the bucket that we just created tony-signed-url-demo
  • Key is combination of fileName and extension will be media name in S3 demo-image.png
  • Expires is the second that the signed url will be expired in
  • ContentType is type of your media image/png , all available here
  • This demo calls AWS directly from local so we need to pass accessKey and secretKey from step 1, when create S3 instance too.
  • When calling s3.getSignedUrlPromis... we pass "putObject" operation as first parameter because we are creating signed url to upload image. For accessing image the operation will be "getObject" we will implement it below

Create first signed-url-access endpoint

Code explain

accessKey , secretKey , Bucket , Key , Expires same as signed-url-upload endpoint, except:

  • Don’t need ContentType , S3 only need Key which is the name of the media stored in S3 to get media (image)
  • Operation passed into s3.getSignedUrlPromis... is "getObject" for accessing

3. Using postman to test

  • Get signed url for uploading image
  • Using signed url to upload image
  • Check S3 bucket to make sure the image is uploaded
  • Get signed url for accessing image
  • Using the signed url to access image

3. Security

As aforementioned, anyone has valid signed url (haven’t expired yet) can access your content, this rarely happen but still. We can do a little bit more to prevent your content is used in other websites by setting permission for your PRIVATE BUCKET

{
"Version": "2012-10-17",
"Id": "http referer policy example",
"Statement": [
{
"Sid": "Deny any domain except yourdomain access your content.",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::tony-signed-url-demo/*",
"Condition": {
"StringNotLike": {
"aws:Referer": [
"https://www.yourdomain.com/*",
"http://yourdomain.com/*"
]
}
}
}
]
}

This policy denies any domain even postman or directly accessing signed url from browser, it only allows your domain to access your content only.

Note: You might get access denied when trying to create this policy, you need to:

  • Uncheck Block all public access
  • Have s3:putBucketPolicy action permission for your user

After add S3 policy, remember to check Block all public access again to keep your bucket private

4. Resources

  • You can find source code here
  • There also is a great article from AWS demo and explain about signed url but it has some unnecessary complicated setup process.

Thanks for your reading.
Happy Coding 🧑‍💻!

--

--