DEV Community

Siddharth
Siddharth

Posted on

How to create a presigned url for accessing AWS S3 images using express ?

AWS S3

S3 is a storage service where we can store files. But when we want to expose those files to a front end or any other service. The particular object ( file ) would need a permission to be accessed for public. There are a few ways to achieve it. One of the ways to achieve that would be using a presigned URL.

What is a Presigned URL ?

Below is a snippet from the AWS documentation,

By default, all S3 objects are private. Only the object owner has permission to access them. However, the object owner can optionally share objects with others by creating a presigned URL, using their own security credentials, to grant time-limited permission to download the objects.

When you create a presigned URL for your object, you must provide your security credentials and then specify a bucket name, an object key, an HTTP method (GET to download the object), and an expiration date and time. The presigned URLs are valid only for the specified duration. If you created a presigned URL using a temporary token, then the URL expires when the token expires, even if the URL was created with a later expiration time.

Anyone who receives the presigned URL can then access the object. For example, if you have a video in your bucket and both the bucket and the object are private, you can share the video with others by generating a presigned URL. Because presigned URLs grant access to your Amazon S3 buckets to whoever has the URL, we recommend that you protect them appropriately.

Generating a presigned URL

Let's create a small service that generates a presigned URL. We will first create a small upload service to upload the object into the bucket. Then we will retrieve that object using a presigned URL.

Setup

Firstly, you would need a AWS account and you need to create a bucket in S3.

I have listed the package.json dependecies below,

"@aws-sdk/client-s3": "^3.186.0",
"@aws-sdk/s3-request-presigner": "^3.186.0",
"cors": "^2.8.5",
"express": "^4.18.1",
"morgan": "^1.10.0",
"multer": "^1.4.5-lts.1",
Enter fullscreen mode Exit fullscreen mode

Once we are ready with our dependecies let's create a index.js file and write the following code

const express = require("express");
const app = express();
const BUCKET_NAME = "YOURBUCKETNAME";
const { getSignedUrl } = require("@aws-sdk/s3-request-presigner");
const { S3Client, GetObjectCommand, ListObjectsCommand, PutObjectCommand } = require("@aws-sdk/client-s3");
app.use(morgan("dev"));
const client = new S3Client({ region: "YOURS3BUCKETREGION" });

app.post("/upload", multer().single("avatar"), async (req, res) => {
const command = new PutObjectCommand({ Bucket: BUCKET_NAME, Body: req.file.buffer, Key: req.file.originalname });
const url = await getSignedUrl(client, command, { expiresIn: 3600 });
const response = await client.send(command);
res.json({ message: "File Uploaded", url: url });
});

app.listen(3001, () => console.log("API is Running is http://localhost:3001"));

Enter fullscreen mode Exit fullscreen mode

From the above code, you can see I am creating a POST endpoint /upload which has a middleware which checks for a file input with key as avatar.

Next, I am creating a command to Put an object into S3 with the BUCKET_NAME and a Body and the Key.

Finally, I am using the getSignedUrl function to get the presigned URL for the object and returning it back as a response.

Let's try uploading an image to S3 bucket.

Uploading Image to S3 using Thunder Client

We have successfully uploaded an image to the bucket and we are able to immediately access the image using the presigned url.

Let's Check the S3 bucket

Verifying S3 bucket that image has been uploaded

In the S3 bucket we can try to open the file we will not be able to access it, Click on the object and try to access the external link in the console.

Object URL Link

Error in access

But if access the presigned URL given back to us we will be able to see the image. But only given for a specific time.

Another Scenario to retrieve the presigned URL

Let's say we have a case where we upload an image into the S3 bucket and we want the retrieve the presigned URL by just getting a single object.

We can use the same pattern like /upload

app.get("/image/:name", async (req, res) => {
    if (req.params.name) {
        const command = new GetObjectCommand({ Bucket: BUCKET_NAME, Key: req.params.name });
        const url = await getSignedUrl(client, command, { expiresIn: 36000 });
        res.json({ url: url });
    } else {
        res.status(404).json({ message: "No Name Found in Key" });
    }
});
Enter fullscreen mode Exit fullscreen mode

As long as we are using a command like GetObjectCommand, PutObjectCommand, we can always use that command and use getSignedUrl function. Key is very important to be given for S3 to identify the object. Key is basically your file name you have uploaded to S3.

We have seen above 2 scenarios on how we can use pre signed URL to retrieve a object from public. Thank you, hope you had fun reading this blog.

Top comments (0)