Authentication
Objective
Section titled “Objective”Every request to every Shelf Cloud API is authenticated. There are no anonymous endpoints.
Read this page to implement a client by hand, to implement the server side, or to diagnose a signature failure.
Requirements
Section titled “Requirements”- An access key id and secret access key
Instructions
Section titled “Instructions”Signature Version 4
Section titled “Signature Version 4”Requests are signed with AWS Signature Version 4 — the same algorithm, not an approximation of it, so that existing clients and SDKs sign correctly without modification.
A signed request carries:
| Header | Contents |
|---|---|
Authorization | Algorithm, credential, signed headers, signature |
X-Amz-Date | The signing timestamp, ISO 8601 basic |
X-Amz-Content-Sha256 | Required by some services; see below |
The Authorization header
Section titled “The Authorization header”Authorization: AWS4-HMAC-SHA256 Credential=AKIAIOSFODNN7EXAMPLE/20260903/hel1/ec2/aws4_request, SignedHeaders=content-type;host;x-amz-date, Signature=5d672d79c15b13162d9279b0855cfba...The Credential parameter is the access key id, a slash, then the credential
scope:
<access-key-id>/<date>/<region>/<service>/aws4_requestThe access key id is not part of the credential scope. It is sent in the
clear as the first element of Credential; the scope is the four elements after
it. A verifier that splits Credential into the wrong number of fields, or that
feeds the key id into the signing key derivation, produces signatures no SDK can
match.
The credential scope
Section titled “The credential scope”20260903/hel1/ec2/aws4_requestThe scope binds a signature to a date, a region and a service. A signature
produced for ec2 in hel1 cannot be replayed against iam, against another
region, or on another day.
This is why the endpoint shape — one host per service per region — cannot change once customers are signing against it.
Signing names
Section titled “Signing names”Each service documents its signing name. It equals the first label of the endpoint host unless the service’s page states otherwise.
That qualification is deliberate: AWS’s own signing names diverge from host prefixes for several services, and stating the rule as a universal would make it wrong the first time we add a service whose counterpart diverges — by which point it is inside every signature.
Global services
Section titled “Global services”A service that is not regional still needs a region in the scope.
PROPOSED: global services are signed with hel1.
PROPOSED: the verifier additionally accepts a signature scoped to the
caller’s own configured region for global services. SDK behaviour when an
endpoint is overridden varies between languages and versions, and a customer
should not receive SignatureDoesNotMatch for a difference we can absorb.
The payload hash
Section titled “The payload hash”The hash of the payload is the final line of the canonical request for every SigV4 request, without exception. A request with no body signs the hash of the empty string.
What is service-specific is the X-Amz-Content-Sha256 header, not the
hashing. Its absence never means the body is unsigned.
A verifier that skips payload hashing for services that do not send that header leaves request bodies unauthenticated: an intermediary could alter the body and the signature would still validate. That is a remote tampering hole, and it is the reason this paragraph is stated as emphatically as it is.
Which headers must be signed
Section titled “Which headers must be signed”SignedHeaders must contain, and the verifier must require:
hostx-amz-date- every
x-amz-*header actually present on the request content-type, when a body is sent
Headers not listed in SignedHeaders are ignored by the server rather than
acted on. A verifier that acts on an unsigned header lets an intermediary change
the meaning of a signed request.
The list above is closed. A vaguer rule — “refuse if any meaningful header is unsigned” — is not implementable, because the server cannot know which headers the client considered meaningful, and two implementers would draw the line differently.
Credentials
Section titled “Credentials”| Element | Notes |
|---|---|
| Access key id | Sent in the clear. PROPOSED: 20 characters, uppercase alphanumeric, with a fixed prefix identifying the credential type |
| Secret access key | Never transmitted. PROPOSED: 40 characters of base64 |
Access key ids are case-sensitive and uppercase. They are the one identifier in the platform that is not lowercase, and a verifier that lowercases them before lookup breaks every signature.
The secret is returned once, at creation, and cannot be retrieved afterwards.
Temporary credentials
Section titled “Temporary credentials”OPEN (Michael): whether temporary credentials exist in v1.
Until they do, a request carrying X-Amz-Security-Token is rejected with
InvalidClientTokenId rather than ignored. Accepting the signature while
discarding the session token would accept a credential the caller believed was
time-limited and scoped — worse than refusing it.
This is not a corner case. The default AWS credential chain supplies a session token in many environments, including assumed roles and SSO, so a customer may send one without intending to.
PROPOSED: when temporary credentials do exist, X-Amz-Security-Token is
part of the canonical request. AWS services differ on whether it is signed or
appended after signing; we pick one and document it, because a client guessing
the other way produces a mismatch every time.
Presigned requests
Section titled “Presigned requests”OPEN (Michael): whether query-string SigV4 — X-Amz-Algorithm,
X-Amz-Credential, X-Amz-Date, X-Amz-Expires, X-Amz-SignedHeaders,
X-Amz-Signature — is supported.
If it is not supported, a request carrying those parameters must be rejected explicitly rather than ignored, so that a customer generating a presigned URL learns immediately rather than discovering an unauthenticated path.
Clock skew
Section titled “Clock skew”PROPOSED: 15 minutes, matching what existing clients expect.
A request outside the window is rejected with RequestExpired and HTTP 400.
Our clock is in the Date header of every response, including errors. The AWS
SDKs use this to correct themselves automatically, but only when the status and
the error code are the ones they recognise — which is why the statuses on the
errors page are not open to preference.
Replay
Section titled “Replay”The skew window is the only bound on replay: a captured signed request can be resent within it by anyone who obtains it — from a log, a proxy, or a trace.
For reads this is disclosure. For creates that accept a client token the damage is bounded, since a replay returns the original result. For creates without one, a replay creates a second billable resource.
OPEN (Michael): whether to maintain a nonce cache to reject exact replays within the skew window, and at what cost.
Rules a verifier must follow
Section titled “Rules a verifier must follow”Stated here because each has produced a real vulnerability in a shipped implementation of this exact protocol:
- Verify possession of the secret. Validating that a signature is well-formed, or that the scope parses, is not authentication. The signature must be recomputed from the derived signing key and compared.
- Compare in constant time. A byte-by-byte comparison that returns early leaks the signature through timing.
- Reject any algorithm other than
AWS4-HMAC-SHA256. An implementation that falls through on an unrecognised algorithm is an authentication bypass. - Resolve
Hostdeliberately. Behind a load balancer, decide once whether the signature is checked againstHostor a forwarded header, and never trust a client-supplied forwarded header — otherwise the host component of the signature is attacker-controlled. - Do not distinguish failures. Wrong secret, wrong region and unknown key return the same error.
What authentication does not decide
Section titled “What authentication does not decide”Authentication establishes who is calling. Authorisation is evaluated separately, against policy. A correctly signed request may still be refused.
Go further
Section titled “Go further”- Errors
- ARNs and identifiers
- Signing requests