Issues short-lived capability tokens for private objects, authorizes HTTP byte-range requests against the same token, forbids durable public URLs, and records the downloading identity in the audit trail.
Package status: reference context ready for human review. The contract and test scenarios are complete, but no claim is made that an adopting implementation has passed them.
Decision
Private objects are never given a durable public ACL. Downloaders receive a short-lived capability token bound to subject, object key, HTTP GET, expiry, and byte-range limits. Range requests (RFC 9110) are first-class: a valid token authorizes a 206 partial response within max_range_bytes. Oversized or unbound ranges are denied. Each successful grant writes files.download.granted with identity and range. Tokens expire independently of the object lifetime. Upload sessions from the related resumable-upload block do not mint download tokens until the object is completed.
Scope
- Authorization to read private blobs, including resume via Range.
- Token TTL, key binding, ACL prohibition, and audit fields.
- Backend issuance and verification of capability tokens or signed URLs that meet this contract.
Outside this block
- How bytes were uploaded or scanned.
- CDN caching of private content (must not convert a token into a public cache key).
- Streaming video DRM.
Contract
- Tokens carry
expires_at; after that instant, GET returnsdownload_token_expiredand zero object bytes. - A live token authorizes
Rangeinbytesup tomax_range_bytes(8388608 in this profile) and may return 206. - A Range larger than
max_range_bytesis denied even if the token is unexpired. - Setting a permanent public ACL on the object is rejected (
public_acl: forbidden). - Successful reads emit
files.download.grantedwithsubject_id,object_key, token id, and the served range. - Tokens are bound to
object_keyandtenant_id; swapping the key in the URL without a matching token fails.
Implementation guidance
- Encode method, key, expiry, and max range on the token. Log token ids, never secrets.
- Normalize Range; reject non-bytes units over
max_range_bytes. Verifier clock has zero skew in this profile.
Failure handling and safeguards
- Failed audit writes deny the download. Incomplete upload sessions cannot mint download tokens.
- Unsatisfiable ranges return 416. Reuse within TTL is allowed; TTL is the theft bound.
Verification and operations
- Tests: expiry, 206 within cap, oversized range, public ACL reject, audit fields.
- Do not cache 206 without capability context. TTL 900 seconds is an adoption value.
The executable-looking examples in this package are fixtures and acceptance contracts. Run
python tools/validate.py from the collection root to check package structure and metadata; then
implement and execute the scenarios in the target repository.
Adoption assumptions
- Names and numeric values in
example.yamlare an adoption profile, not universal defaults. - The adopting team must map actors, data classes, error vocabulary, and ownership to its system.