Buckets in your code

A bucket speaks S3, so the SDK you'd use for Amazon S3 works with it, given the five variables connecting an app puts in its environment. Two settings differ from Amazon's defaults: path-style addressing, and the region auto.

In your code

Buckets use path-style addressing and the region auto. With the AWS SDK for JavaScript:

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

const s3 = new S3Client({
  endpoint: process.env.S3_ENDPOINT,
  region: process.env.S3_REGION,
  forcePathStyle: true,
  credentials: {
    accessKeyId: process.env.S3_ACCESS_KEY_ID,
    secretAccessKey: process.env.S3_SECRET_ACCESS_KEY,
  },
});

await s3.send(new PutObjectCommand({ Bucket: process.env.S3_BUCKET, Key: "avatars/ada.png", Body: file }));

With boto3 (Python):

import os, boto3
from botocore.config import Config

s3 = boto3.client(
    "s3",
    endpoint_url=os.environ["S3_ENDPOINT"],
    region_name=os.environ["S3_REGION"],
    aws_access_key_id=os.environ["S3_ACCESS_KEY_ID"],
    aws_secret_access_key=os.environ["S3_SECRET_ACCESS_KEY"],
    config=Config(s3={"addressing_style": "path"}),
)

From your own computer, the AWS CLI works with the key you were shown:

aws s3 ls s3://uploads-k3m9x2ab --endpoint-url https://storage.smartalfred.com --region auto

Files for browsers

Buckets aren't public: every request is signed with the bucket's key. To let a browser download a file, or upload one straight to the bucket, give it a presigned URL, made by your app with its SDK (getSignedUrl in JavaScript, generate_presigned_url in boto3). Presigned URLs work from any website: there's no CORS to set up.

What works

Objects in and out, with metadata, ranges and conditional requests; copying within the bucket; listing (with prefixes and delimiters, so folders work); deleting many at once; multipart uploads for large files; presigned URLs.

Not supported: public buckets, versioning, object tags and ACLs, lifecycle rules, and copying between buckets (a key opens one bucket).