How To Fix - CORS Error while uploading files on Cloudflare R2 using presigned URLs.

This post was originally posted here at my blog.

Cloudflare R2 Storage allows developers to store large amounts of unstructured data without the costly egress bandwidth fees associated with typical cloud storage services.

While using R2 to upload files with presigned URLs, I started getting the following CORS issue in my browser console: "Access to fetch at '' from origin localhost:3000 has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled."

Here is how I solved it using aws-sdk for js V3:

Create an empty node project and install aws-sdk for js v3.

mkdir r2-cors && cd r2-cors
pnpm init
pnpm install @aws-sdk/client-s3 @aws-sdk/s3-request-presigner
touch cors.js

Add type: "module" into your package.json file.

Next, copy and paste this snippet into cors.js and replace the credentials from your Cloudflare R2 dashboard. Refer here to create the tokens.

import { PutBucketCorsCommand, S3Client } from "@aws-sdk/client-s3";

const s3Client = new S3Client({
  region: "auto",
  endpoint: `https://${CF-ACCOUNT-ID}.r2.cloudflarestorage.com`, //TODO: replace
  credentials: {
    accessKeyId: `${ACCESS-KEY}`, //TODO: replace
    secretAccessKey: `${ACCESS-SECRET}`, //TODO: replace
  },
});

async function main() {
  const response = await s3Client.send(
    new PutBucketCorsCommand({
      Bucket: "your-bucket-name", //TODO: replace
      CORSConfiguration: {
        CORSRules: new Array({
          AllowedHeaders: ["content-type"], //this is important, do not use "*"
          AllowedMethods: ["GET", "PUT", "HEAD"],
          AllowedOrigins: ["*"],
          ExposeHeaders: [],
          MaxAgeSeconds: 3000,
        }),
      },
    })
  );
  console.dir(repsonse)
}

main();

Then run the script with node:

node cors.js

If everything works well, you should see the following logged in the console:

{
  '$metadata': {
    httpStatusCode: 200,
    requestId: undefined,
    extendedRequestId: undefined,
    cfId: undefined,
    attempts: 1,
    totalRetryDelay: 0
  }
}

And that's it, your CORS issue should be resolved now.

If you have any questions or just want to connect, follow me on Twitter.