AWS  

Fix AWS S3 Upload CORS Error (Frontend + .NET Core Example)

⚠️ Common Problem

If you’re uploading files to AWS S3 directly from the browser using a pre-signed URL (via JavaScript and a .NET Core API), you’ve probably faced this frustrating error:

Access to fetch at 'https://your-bucket.s3.amazonaws.com/...' 
from origin 'http://localhost:3000' has been blocked by CORS policy: 
No 'Access-Control-Allow-Origin' header is present on the requested resource.

This happens because your S3 bucket does not allow requests from your frontend domain.

In this article, we’ll fix it step-by-step for both AWS S3 and your .NET Core API, with real working code and links to official AWS docs.

🧠 What is CORS?

CORS (Cross-Origin Resource Sharing) is a security feature of browsers that blocks JavaScript code from making requests to another domain unless explicitly allowed.

When your frontend (localhost:3000 or myapp.com) tries to upload to S3 (s3.amazonaws.com), the browser asks:

β€œDoes this S3 bucket allow requests from my origin?”

If not, the request is blocked β€” even before reaching AWS.

🧱 Step 1. Configure CORS in Your AWS S3 Bucket

1️⃣ Go to your AWS S3 Console
2️⃣ Select your bucket β†’ Permissions tab β†’ Scroll to Cross-origin resource sharing (CORS)
3️⃣ Click Edit, and paste the following configuration:

[{
    "AllowedHeaders": ["*"],
    "AllowedMethods": ["GET", "PUT", "POST"],
    "AllowedOrigins": ["http://localhost:3000", "https://yourdomain.com"],
    "ExposeHeaders": ["ETag"],
    "MaxAgeSeconds": 3000}]

🧾 Explanation

KeyDescription
AllowedOriginsDomains allowed to access the bucket (add your frontend URLs)
AllowedMethodsHTTP methods allowed (PUT for upload, GET for fetch)
AllowedHeadersRequired when sending custom headers
ExposeHeadersLets browser read specific headers (e.g., ETag)
MaxAgeSecondsCache time for preflight results

πŸ”— Official AWS Docs: Configuring CORS for S3

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

Create an endpoint in your .NET Core project to generate a pre-signed URL:

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"
            };

            var url = _s3Client.GetPreSignedURL(request);

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

πŸ‘‰ This API safely generates a short-lived pre-signed upload URL that your frontend can use.

πŸ–₯️ Step 3. Upload File from JavaScript (Frontend)

Here’s a minimal HTML + JavaScript example:

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

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

      // Step 1: Ask API for presigned URL
      const res = await fetch(`https://localhost:5001/api/S3Upload/generate-url?fileName=${file.name}`);
      const data = await res.json();

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

      if (uploadRes.ok) {
        document.getElementById("msg").innerText = "βœ… Upload Successful!";
        console.log("File URL:", data.fileUrl);
      } else {
        document.getElementById("msg").innerText = "❌ Upload Failed!";
      }
    });
  </script>
</body>
</html>

βœ… Once your S3 CORS settings are correct, the upload will succeed directly from the browser.

πŸ” Step 4. Enable CORS in .NET Core API (Optional)

If your frontend and backend run on different ports (e.g., React on 3000 and API on 5001), enable CORS in your .NET API as well.

In Program.cs:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddCors(options =>
{
    options.AddPolicy("AllowFrontend", policy =>
    {
        policy.WithOrigins("http://localhost:3000", "https://yourdomain.com")
              .AllowAnyHeader()
              .AllowAnyMethod();
    });
});

builder.Services.AddControllers();
builder.Services.AddAWSService<IAmazonS3>();

var app = builder.Build();
app.UseCors("AllowFrontend");
app.MapControllers();
app.Run();

πŸ§ͺ Step 5. Test and Verify

  1. Run your .NET Core API (https://localhost:5001)

  2. Serve your frontend app (http://localhost:3000)

  3. Select a file and click Upload

βœ… The file should appear in your S3 bucket β†’ uploads/ folder.
βœ… The browser console should show no CORS errors.

🧾 Common Mistakes & Fixes

IssueFix
❌ Still getting CORS errorEnsure AllowedOrigins includes exact domain, not * if using PUT.
❌ 403 ForbiddenCheck IAM user permissions (s3:PutObject and bucket policy).
❌ Wrong Content-TypeMatch ContentType between .NET API and JavaScript upload request.
❌ Mixed HTTP/HTTPSAlways use the same scheme (e.g., both HTTPS).

πŸ“š References

  • πŸ”— AWS Docs – Configure CORS for S3

  • πŸ”— .NET AWS SDK for S3

  • πŸ”— MDN Web Docs – CORS Explained

  • πŸ”— Fix CORS Error in JavaScript Fetch

πŸš€ Summary

StepDescription
1️⃣Add proper CORS JSON configuration in your S3 bucket
2️⃣Create pre-signed URL API in .NET Core
3️⃣Upload file directly from browser using fetch()
4️⃣Enable CORS in your .NET API if needed
5️⃣Test and confirm successful upload without CORS error

βœ… Now your S3 uploads will work seamlessly from any frontend β€” React, Angular, or even plain HTML β€” with no CORS errors and secure access via pre-signed URLs.