Skip to main content

PutObjectAcl

PutObjectAcl sets an object's access control list (ACL) - who may do what with the object. On STRG, objects share their bucket's ACL rather than carrying one of their own: private when the bucket is Protected, and public-read when its Bucket Protection is off. A request that names the ACL the bucket already has succeeds and leaves everything as it was, which keeps tools that set an object's ACL after each upload working as they are. One setting per bucket decides who can read its objects, and PutBucketAcl is the way to change it for every object at once. GetObjectAcl reads an object's ACL.

Good to know on STRG
  • The ACL travels in the x-amz-acl header, as private or public-read - the same value as the bucket's ACL.
  • A canned ACL different from the bucket's answers 501 NotImplemented, so a client knows straight away that the object follows its bucket.
  • An AccessControlPolicy body and the x-amz-grant-* headers answer 501 NotImplemented too: the canned ACL is the way to say it.
  • The key needs Manage buckets, a permission for keys with access to all buckets, rather than a write permission on objects.
  • x-amz-expected-bucket-owner is welcome and has nothing to check: a key only ever reaches buckets of its own account.

When you'd use it​

  • Tools written for Amazon S3. Upload tools, sync clients and backup scripts that set an object's ACL right after uploading it - private for a nightly backup, public-read for a website's images - carry on as usual, as long as they ask for the ACL their bucket already has.
  • Confirming a setting. A script or an agent publishing files can send the ACL it expects the object to have; a 200 OK confirms the bucket gives the object exactly that access.

Request​

PUT /photos/2024/cat.jpg?acl HTTP/1.1
Host: my-bucket.s3.eu-central-1.strg.com
Authorization: AWS4-HMAC-SHA256 Credential=...
x-amz-date: 20260926T120000Z
x-amz-content-sha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
x-amz-acl: private
Content-Length: 0

The path-style form is PUT /my-bucket/photos/2024/cat.jpg?acl on s3.eu-central-1.strg.com - Addressing explains both.

Permissions​

The access key needs Manage buckets (buckets:write), a permission held by keys with access to all buckets. For a key limited to a key prefix, the object's key starts with that prefix. Anything else answers 403 AccessDenied. Access keys has the details.

URI parameters​

NameTypeRequiredDescription
BucketStringYesThe bucket that holds the object.
KeyStringYesThe object's key. A key containing a . or .. path segment (a/../b) cannot be put in a URL and answers 400 InvalidURI; its ACL is its bucket's already.
aclFlagYesSelects the ACL subresource. Sent with no value.
versionIdStringNoA specific version of the object. Without it, the current version is used.

Any other query parameter answers 501 NotImplemented (presigning's X-Amz-* parameters aside).

Request headers​

NameTypeRequiredDescription
x-amz-aclStringYesThe canned ACL: private or public-read, matching the bucket's ACL. A value different from the bucket's answers 501 NotImplemented, and so does any other canned ACL (public-read-write, authenticated-read, bucket-owner-full-control, ...).
x-amz-grant-full-controlStringNoSTRG answers 501 NotImplemented; the object's access is its bucket's.
x-amz-grant-readStringNoSTRG answers 501 NotImplemented; the object's access is its bucket's.
x-amz-grant-read-acpStringNoSTRG answers 501 NotImplemented; the object's access is its bucket's.
x-amz-grant-writeStringNoSTRG answers 501 NotImplemented; the object's access is its bucket's.
x-amz-grant-write-acpStringNoSTRG answers 501 NotImplemented; the object's access is its bucket's.
Content-MD5StringNoWelcome. The request has no body, so there is nothing for it to protect.
x-amz-sdk-checksum-algorithmStringNoWelcome, together with the checksum header the SDK sends beside it.
x-amz-request-payerStringNoHas no effect: STRG has no Requester Pays buckets, so there is never a need to send it.
x-amz-expected-bucket-ownerStringNoWelcome, with nothing to check: an access key only ever reaches its own account's buckets.

Every x-amz-* header in the request is part of its signature.

Request body​

None. The ACL is said entirely by x-amz-acl, so an AccessControlPolicy document answers 501 NotImplemented.

Response​

Response headers​

NameDescription
x-amz-request-idThe request ID, handy for a support request.
x-amz-version-idThe version of the object whose ACL was set.

x-amz-request-charged is never returned, since STRG has no Requester Pays.

Response body​

None. A successful request answers 200 OK with an empty body.

Errors​

These are the errors this request can return, and the situation behind each one.

CodeHTTP statusWhen
NotImplemented501x-amz-acl differs from the bucket's ACL, or the request carries an AccessControlPolicy body, an x-amz-grant-* header, a canned ACL other than private or public-read, or a query parameter other than acl and versionId (presigning's X-Amz-* parameters aside).
NoSuchKey404The object does not exist.
NoSuchBucket404The bucket does not exist, it is in a region other than the endpoint's, or the account has no storage in this endpoint's region yet.
AccessDenied403The access key lacks Manage buckets, the object's key is outside its key prefix, the account is not active, an x-amz-* header is unsigned, or the request is unsigned.
InvalidAccessKeyId403The access key does not exist, has expired or been revoked - or it was created moments ago and is not usable yet in this region where the account already stores data, in which case the same request works shortly afterwards.
InvalidURI400The key contains a . or .. path segment.
SignatureDoesNotMatch403The request signature does not match.
RequestTimeTooSkewed403The request time is more than 15 minutes from the server's.
AuthorizationHeaderMalformed400The signature's credential scope names a region other than the endpoint's.
SlowDown503Too many requests. The Retry-After header says when a retry is welcome; the AWS SDKs retry on their own.
ServiceUnavailable503A temporary failure; the same request can be retried.
InternalError500An unexpected failure; the same request can be retried.

Differences from Amazon S3​

The table lists each place where STRG behaves differently, and what that means for a client.

AspectAmazon S3STRG
Per-object ACLsEach object has its own ACLAn object's ACL is always its bucket's - one setting per bucket, changed with PutBucketAcl
x-amz-aclAny canned ACL, applied to the objectprivate or public-read, matching the bucket's current ACL. Any other value answers 501 NotImplemented
Explicit grantsx-amz-grant-* headers or an AccessControlPolicy body501 NotImplemented: the canned ACL says it all
PermissionWRITE_ACP on the object (s3:PutObjectAcl)Manage buckets, on a key with access to all buckets
Bucket in another region301 redirect with x-amz-bucket-region404 NoSuchBucket. A bucket is reached through its own regional endpoint
Keys with . or .. segmentsAllowed400 InvalidURI. Such a key's ACL is its bucket's already
x-amz-expected-bucket-ownerChecked against the bucket ownerWelcome, with nothing to check

Examples​

Setting the ACL of photos/2024/cat.jpg in a Protected bucket, whose ACL is private:

aws s3api put-object-acl \
--bucket my-bucket \
--key photos/2024/cat.jpg \
--acl private \
--endpoint-url https://s3.eu-central-1.strg.com \
--region eu-central-1

A script that does not know the bucket's setting can read the bucket's ACL first and send the same one, so the request succeeds whichever Bucket Protection setting the bucket has:

ACL=$(aws s3api get-bucket-acl \
--bucket my-bucket \
--endpoint-url https://s3.eu-central-1.strg.com \
--region eu-central-1 \
--query "length(Grants[?Grantee.URI=='http://acs.amazonaws.com/groups/global/AllUsers'])" \
--output text)

if [ "$ACL" -gt 0 ]; then ACL=public-read; else ACL=private; fi

aws s3api put-object-acl \
--bucket my-bucket \
--key photos/2024/cat.jpg \
--acl "$ACL" \
--endpoint-url https://s3.eu-central-1.strg.com \
--region eu-central-1

Reading the bucket's ACL takes Read bucket settings, which every access key holds - GetBucketAcl has the details.

View as Markdown