AWS  

Upload Image to AWS S3 Using JavaScript and Pre-Signed URL (with .NET Core API)

Amazon S3 (Simple Storage Service) is one of the most reliable ways to store and serve files like images, videos, and documents.

In this tutorial, you’ll learn how to upload an image directly from the browser to your S3 bucket using JavaScript, while your .NET Core backend securely generates a pre-signed URL.

🧩 What Is a Pre-Signed URL?

A pre-signed URL is a temporary, secure URL generated by AWS SDK that allows you to upload (PUT) or download (GET) files directly from/to S3 without exposing your AWS credentials.

πŸ‘‰ Official AWS Docs: Pre-Signed URLs

πŸ› οΈ Prerequisites

Before starting, make sure you have:

  • An AWS account with S3 bucket access

  • An IAM user with AmazonS3FullAccess or a custom policy that allows:

    {"Version": "2012-10-17","Statement": [
        {
          "Effect": "Allow",
          "Action": ["s3:PutObject", "s3:GetObject"],
          "Resource": "arn:aws:s3:::your-bucket-name/*"
        }]}
  • A .NET 6+ Web API project

  • A JavaScript (HTML) frontend

🧱 Step 1. Install AWS SDK in .NET Core

Install AWS SDK via NuGet:

dotnet add package AWSSDK.S3

βš™οΈ Step 2. Create Pre-Signed URL API in .NET Core

Here’s a working example controller to generate a pre-signed URL for S3 upload.

using Amazon.S3;
using Amazon.S3.Model;
using Microsoft.AspNetCore.Mvc;
using System;

namespace AwsUploadDemo.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class S3UploadController : ControllerBase
    {
        private readonly IAmazonS3 _s3Client;
        private const string BucketName = "your-bucket-name";

        public S3UploadController(IAmazonS3 s3Client)
        {
            _s3Client = s3Client;
        }

        [HttpGet("generate-url")]
        public IActionResult GeneratePresignedUrl(string fileName)
        {
            var key = $"uploads/{Guid.NewGuid()}_{fileName}";
            var request = new GetPreSignedUrlRequest
            {
                BucketName = BucketName,
                Key = key,
                Verb = HttpVerb.PUT,
                Expires = DateTime.UtcNow.AddMinutes(10),
                ContentType = "image/jpeg"
            };

            string presignedUrl = _s3Client.GetPreSignedURL(request);

            return Ok(new
            {
                uploadUrl = presignedUrl,
                fileUrl = $"https://{BucketName}.s3.amazonaws.com/{key}"
            });
        }
    }
}

βœ… What this does:

  • Generates a temporary URL valid for 10 minutes.

  • Allows HTTP PUT upload directly to S3.

  • Returns both the upload URL and the final public file URL.

πŸ–ΌοΈ Step 3. Upload Image Using JavaScript (Frontend)

Create a simple index.html page with a file input and an upload button.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>AWS S3 Upload via Pre-Signed URL</title>
</head>
<body>
  <h2>Upload Image to AWS S3</h2>
  <input type="file" id="fileInput" accept="image/*" />
  <button id="uploadBtn">Upload</button>

  <p id="status"></p>
  <img id="preview" width="200" style="margin-top:10px;" />

  <script>
    document.getElementById("uploadBtn").addEventListener("click", async () => {
      const fileInput = document.getElementById("fileInput");
      const file = fileInput.files[0];
      if (!file) return alert("Please select an image!");

      // 1️⃣ Request Pre-signed URL from .NET API
      const response = await fetch(`https://localhost:5001/api/S3Upload/generate-url?fileName=${file.name}`);
      const data = await response.json();

      // 2️⃣ Upload file directly to S3 using PUT
      const uploadResponse = await fetch(data.uploadUrl, {
        method: "PUT",
        headers: {
          "Content-Type": file.type
        },
        body: file
      });

      if (uploadResponse.ok) {
        document.getElementById("status").innerText = "βœ… Upload Successful!";
        document.getElementById("preview").src = data.fileUrl;
      } else {
        document.getElementById("status").innerText = "❌ Upload Failed!";
      }
    });
  </script>
</body>
</html>

βœ… Flow Explanation

  1. User selects an image.

  2. Frontend requests a pre-signed upload URL from the backend.

  3. File is uploaded directly to S3 via PUT request.

  4. Final image URL is shown to the user.

πŸ” Step 4. Secure Your S3 Bucket

To make uploaded images publicly accessible, you can use a bucket policy like:

{"Version": "2012-10-17","Statement": [
    {
      "Sid": "PublicReadForGetBucketObjects",
      "Effect": "Allow",
      "Principal": "*",
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::your-bucket-name/*"
    }]}

Alternatively, you can keep the bucket private and use signed GET URLs for access.

⚑ Bonus Tips

  • 🧠 For multiple file uploads, call the same API for each file.

  • πŸ”’ For secure uploads, validate the user session before generating the pre-signed URL.

  • βš™οΈ Use AWS SDK v3 for JavaScript if you need server-side uploads in Node.js.

πŸ“š References

  • πŸ”— AWS SDK for .NET Documentation

  • πŸ”— Using Pre-Signed URLs for S3

  • πŸ”— AWS IAM Policies Guide

  • πŸ”— CORS Configuration for S3

🧾 Summary

StepDescription
1️⃣Create a .NET API to generate a pre-signed URL
2️⃣Configure AWS S3 permissions
3️⃣Use JavaScript fetch() to PUT the image directly
4️⃣Display uploaded image URL

With this approach, you offload the heavy lifting to the browser and keep your API secure β€” a perfect balance between performance and safety.