Applying CORS policies
By default, browsers block requests from a website (https://app.example.com) to a different origin such as https://Bucketname.s3.internet1.de. By setting up a CORS configuration on the bucket, you can specifically allow such cross-origin access – for example, for direct uploads from the browser or for loading fonts and media via JavaScript.
When do I need CORS?
fetch()/XMLHttpRequestprocessing of objects from the browser (including with pre-signed URLs)- Browser uploads directly to the bucket (pre-signed PUT/POST)
- Web fonts, WebGL textures,
<canvas>processing of images from the bucket
CORS is not required for server-side access (CLI, back-end SDKs) or simple integration via <img src=…>.
Setting CORS rules
cors.json:
{
"CORSRules": [
{
"AllowedOrigins": ["https://app.example.com"],
"AllowedMethods": ["GET", "HEAD", "PUT"],
"AllowedHeaders": ["*"],
"ExposeHeaders": ["ETag"],
"MaxAgeSeconds": 3600
}
]
}
aws s3api put-bucket-cors --bucket mein-bucket \
--cors-configuration file://cors.json \
--endpoint-url https://s3.internet1.de
Fields at a glance
| Field | Meaning |
|---|---|
AllowedOrigins | Permitted origins (scheme + host + port). * permits all – use only for public, non-critical content. |
AllowedMethods | GET, HEAD, PUT, POST, DELETE |
AllowedHeaders | Headers that the browser is permitted to send (e.g. Content-Type, x-amz-*); * for all |
ExposeHeaders | Response headers that JavaScript is permitted to read – ETag is required for multipart uploads in the browser |
MaxAgeSeconds | Cache duration of the preflight response in the browser |
Several rules are possible; the first one that fits wins.
Check and remove the configuration
aws s3api get-bucket-cors --bucket mein-bucket --endpoint-url https://s3.internet1.de
aws s3api delete-bucket-cors --bucket mein-bucket --endpoint-url https://s3.internet1.de
Testing CORS
Simulate a pre-flight request:
curl -i -X OPTIONS "https://mein-bucket.s3.internet1.de/test.txt" \
-H "Origin: https://app.example.com" \
-H "Access-Control-Request-Method: PUT"
If the rule applies, the answer includes, amongst other things, Access-Control-Allow-Origin: https://app.example.com.
Common mistakes
| Symptom | Cause | Solution |
|---|---|---|
| Console reports blocked by CORS policy | Origin not in AllowedOrigins | Enter the exact origin (including https://, without the path, and the port if applicable) |
| PUT upload fails, GET works | PUT missing from AllowedMethods or Content-Type not in AllowedHeaders | Add method/header |
| Multipart upload in the browser hangs after parts | ETag not in ExposeHeaders | Set "ExposeHeaders": ["ETag"] |
| Change does not take effect immediately | Preflight cached in the browser | Wait for MaxAgeSeconds or try a hard reload/incognito mode |
CORS is not an access control mechanism, but merely a browser-based authorisation mechanism. Private objects remain protected by ACLs and signatures – conversely, a restrictive CORS rule does not protect public objects from being downloaded outside the browser.