DEV Community

Cover image for How can you upload an image in AWS S3 bucket directly with presigned URL
Tanmoy Bhowmick
Tanmoy Bhowmick

Posted on

How can you upload an image in AWS S3 bucket directly with presigned URL

Why you should use this method?

Firstly, with the presigned URL, you don't have to send your file to the backend to upload it to the S3 bucket; you can directly upload the file from your front-end application to the S3 bucket securely. It's a convenient and secure approach. This URL can be provided to your users to grant temporary access to a specific S3 object.

How to use the presigned URL

  1. Create an S3 bucket

Here, I am creating an S3 bucket through a CloudFormation template in YAML with minimal configuration. You can also create it from the AWS console or convert it to JSON.

resources:
  Resources:
    MyS3Bucket:
      Type: AWS::S3::Bucket
      Properties:
        BucketName: My-S3-Bucket-Name
        VersioningConfiguration:
          Status: Enabled
        CorsConfiguration:
          CorsRules:
            - AllowedMethods:
                - GET
                - PUT
                - POST
                - HEAD
              AllowedOrigins:
                - "*"
              AllowedHeaders:
                - "*"

    MyS3BucketPolicy: 
      Type: 'AWS::S3::BucketPolicy'
      Properties:
        Bucket: !Ref MyS3Bucket
        PolicyDocument:
          Statement:
            - Action:
                - 's3:GetObject'
              Effect: Allow
              Resource: !Join
                - ''
                - - 'arn:aws:s3:::'
                  - !Ref MyS3Bucket
                  - /*
              Sid: "PublicReadGetObject"
              Principal: '*'
Enter fullscreen mode Exit fullscreen mode
  1. Make a Lambda function to get a signed URL
const AWS = require("aws-sdk");
const region = process.env.REGION;
AWS.config.update({ region });
const s3 = new AWS.S3();

async function getPresignedUploadUrl(event) {
  const { bucket, directory, fileName } = event;

  const key = `${directory}/${fileName}`;

  const url = await s3.getSignedUrl("putObject", {
    Bucket: bucket,
    Key: key,
    ContentType: "image/*",
    Expires: 300
  });
  return url;
}

module.exports = { getPresignedUploadUrl };
Enter fullscreen mode Exit fullscreen mode
  1. Function to get the signed URL in the frontend
const getS3Signeture = async (name) => {
  // name = name of the current selected file EG: image.jpg
  const result = await axios.post("ENDPOINT-OF-THE-getPresignedUploadUrl-LAMBDA", {
    bucket: "My-S3-Bucket-Name",
    directory: "FOLDER-NAME",
    fileName: Date.now() + name,
  });
  return result.data;
};

export default getS3Signeture;
Enter fullscreen mode Exit fullscreen mode
  1. Function to upload the file to S3 with the presigned URL
const s3UploadImage = async (presignedUploadUrl, file) => {
  const response = await fetch(
    new Request(presignedUploadUrl, {
      method: "PUT",
      body: file,
      headers: new Headers({
        "Content-Type": "image/*",
        ACL: "public-read",
      }),
    })
  );

  if (response.status === 200) {
    const data = {
      url: response.url.split("?")[0],
      status: 200,
    };
    return data;
  } else {
    const failed = {
      url: "",
      status: 500,
    };

    return failed;
  }
};

export default s3UploadImage;
Enter fullscreen mode Exit fullscreen mode

Please note that you may need to adapt the code to your specific use case and environment. Additionally, ensure you have the necessary dependencies such as Axios for making HTTP requests.

Top comments (0)