Diagnose and fix CORS configuration errors
Diagnoses and fixes CORS configuration errors for R2 buckets with test commands and security best practices.
/plugin marketplace add secondsky/claude-skills/plugin install cloudflare-r2@claude-skillsSystematically diagnose and fix CORS (Cross-Origin Resource Sharing) configuration issues for R2 buckets.
{{bucket_name}}{{origin}}{{methods}}{{error_message}}| Error Message | Cause | Fix |
|---|---|---|
| "No 'Access-Control-Allow-Origin' header" | Missing origin in AllowedOrigins | Add your domain |
| "Method PUT is not allowed" | Method not in AllowedMethods | Add PUT to allowed methods |
| "Header 'Content-Type' not allowed" | Header not in AllowedHeaders | Add Content-Type |
| "Credentials mode requires specific origin" | Using wildcard with credentials | Use specific origin |
[
{
"AllowedOrigins": [
"https://example.com",
"https://www.example.com"
],
"AllowedMethods": [
"GET",
"PUT",
"POST",
"DELETE"
],
"AllowedHeaders": [
"Content-Type",
"Authorization",
"X-Requested-With"
],
"ExposeHeaders": [
"ETag",
"Content-Length"
],
"MaxAgeSeconds": 3600
}
]
# Test preflight request (OPTIONS)
curl -v \
-H "Origin: https://example.com" \
-H "Access-Control-Request-Method: PUT" \
-H "Access-Control-Request-Headers: Content-Type" \
-X OPTIONS \
"https://{{bucket_name}}.{{account_id}}.r2.cloudflarestorage.com/test.txt"
# Expected response headers:
# Access-Control-Allow-Origin: https://example.com
# Access-Control-Allow-Methods: GET, PUT, POST, DELETE
# Access-Control-Allow-Headers: Content-Type
# Access-Control-Max-Age: 3600
# Test actual request (PUT)
curl -v \
-H "Origin: https://example.com" \
-H "Content-Type: text/plain" \
-X PUT \
"https://{{bucket_name}}.{{account_id}}.r2.cloudflarestorage.com/test.txt" \
-d "Test data"
# Expected response headers:
# Access-Control-Allow-Origin: https://example.com
# Access-Control-Expose-Headers: ETag
{
"AllowedOrigins": ["https://myapp.com"],
"AllowedMethods": ["PUT", "POST"],
"AllowedHeaders": ["Content-Type"],
"MaxAgeSeconds": 3600
}
{
"AllowedOrigins": ["https://myapp.com"],
"AllowedMethods": ["GET", "HEAD"],
"AllowedHeaders": ["Range"],
"ExposeHeaders": ["ETag", "Content-Length", "Content-Range"],
"MaxAgeSeconds": 3600
}
{
"AllowedOrigins": ["http://localhost:3000"],
"AllowedMethods": ["GET", "PUT", "POST", "DELETE", "HEAD"],
"AllowedHeaders": ["*"],
"MaxAgeSeconds": 3600
}