Create a signed AWS API request
Important
If you use an AWS SDKs (see
Sample Code
and Libraries
In Regions that support multiple signature versions, manually signing requests mean you must specify which signature version is used. When you supply requests to Multi-Region Access Points, SDKs and the CLI automatically switch to using Signature Version 4A without additional configuration.
The following is an overview of the process to create a signed request. To calculate a signature, you first need a string to sign. You then calculate a HMAC-SHA256 hash of the string to sign by using a signing key. The following diagram illustrates the process, including the various components of the string that you create for signing.
The following table describes the functions that are shown in the diagram. You need to implement code for these functions. For more information, see the code examples in the AWS SDKs .
URI encode every byte except the unreserved characters: 'A'-'Z', 'a'-'z', '0'-'9', '-', '.', '_', and '~'.
The space character is a reserved character and must be encoded as "%20" (and not as "+").
Each URI encoded byte is formed by a '%' and the two-digit hexadecimal value of the byte.
Letters in the hexadecimal value must be uppercase, for example "%1A".
Encode the forward slash character, '/',
everywhere except in the object key name. For example, if
the object key name is
photos/Jan/sample.jpg
,
the forward slash in the key name is not encoded.
Important
The standard UriEncode functions provided by your development platform may not work because of differences in implementation and related ambiguity in the underlying RFCs. We recommend that you write your own custom UriEncode function to ensure that your encoding will work.
To see an example of a UriEncode function in Java, see
Java Utilities
Function | Description |
---|
Note
When signing your requests, you can use either AWS Signature Version 4 or AWS
Signature Version 4A. The key difference between the two is determined by how the
signature is calculated. With AWS Signature Version 4A, the signature does not
include Region-specific information and is calculated using the
AWS4-ECDSA-P256-SHA256
algorithm.
Temporary security credentials
Instead of using long-term credentials to sign a request, you can use temporary security credentials provided by AWS Security Token Service (AWS STS).
When you use temporary security credentials, you must add
X-Amz-Security-Token
to the Authorization header or the query
string to hold the session token. Some services require that you add
X-Amz-Security-Token
to the canonical request. Other services
require only that you add
X-Amz-Security-Token
at the end, after you
calculate the signature. Check the documentation for each AWS service for
details.
Summary of signing steps
Step 1: Create a canonical request
Arrange the contents of your request (host, action, headers, etc.) into a standard canonical format. The canonical request is one of the inputs used to create a string to sign. For details, see Elements of an AWS API request signature .
Step 2: Create a hash of the canonical request
Derive a signing key by performing a succession of keyed hash operations (HMAC operations) on the request date, Region, and service, with your AWS secret access key as the key for the initial hashing operation.
Step 3: Create a String to Sign
Create a string to sign with the canonical request and extra information such as the algorithm, request date, credential scope, and the digest (hash) of the canonical request.
Step 4: Calculate the signature
After you derive the signing key, you then calculate the signature by performing a keyed hash operation on the string to sign. Use the derived signing key as the hash key for this operation.
Step 5: Add the signature to the request
After you calculate the signature, add it to an HTTP header or to the query string of the request.
Step 1: Create a canonical request
Create a canonical request by concatenating the following strings, separated by newline characters. This helps ensure that the signature that you calculate and the signature that AWS calculates can match.
<HTTPMethod>
\n<CanonicalURI>
\n<CanonicalQueryString>
\n<CanonicalHeaders>
\n<SignedHeaders>
\n<HashedPayload>
CanonicalUri
– The URI-encoded version of
the absolute path component URI, starting with the "/" that follows the
domain name and up to the end of the string or to the question mark
character ('?') if you have query string parameters. If the absolute path is
empty, use a forward slash character (/). The URI in the following example,
/examplebucket/myphoto.jpg
, is the absolute path and you
don't encode the "/" in the absolute path:
http://s3.amazonaws.com/examplebucket/myphoto.jpg
CanonicalQueryString
– The URI-encoded
query string parameters. You URI-encode each name and values individually.
You must also sort the parameters in the canonical query string
alphabetically by key name. The sorting occurs after encoding. The query
string in the following URI example is:
http://s3.amazonaws.com/examplebucket?prefix=somePrefix&marker=someMarker&max-keys=2
The canonical query string is as follows (line breaks are added to this example for readability):
UriEncode("marker")+"="+UriEncode("someMarker")+"&"+ UriEncode("max-keys")+"="+UriEncode("20") + "&" + UriEncode("prefix")+"="+UriEncode("somePrefix")
When a request targets a subresource, the corresponding query parameter
value will be an empty string (""). For example, the following URI
identifies the
ACL
subresource on the
examplebucket
bucket:
http://s3.amazonaws.com/examplebucket?acl
The CanonicalQueryString in this case is as follows:
UriEncode("acl") + "=" + ""
If the URI does not include a '?', there is no query string in the request, and you set the canonical query string to an empty string (""). You will still need to include the "\n".
CanonicalHeaders
– A list of request
headers with their values. Individual header name and value pairs are
separated by the newline character ("\n"). The following is an example of a
canonicalheader:
Lowercase(
<HeaderName1>
)+":"+Trim(<value>
)+"\n" Lowercase(<HeaderName2>
)+":"+Trim(<value>
)+"\n" Lowercase(<HeaderNameN>
)+":"+Trim(<value>
)+"\n"
CanonicalHeaders list must include the following:
If the
Content-Type
header is present in the request,
you must add it to the
CanonicalHeaders
list.
Any
x-amz-*
headers that you plan to include in your
request must also be added. For example, if you are using temporary
security credentials, you need to include
x-amz-security-token
in your request. You must add
this header in the list of
CanonicalHeaders
.
Note
The
x-amz-content-sha256
header is required for Amazon S3
AWS requests. It provides a hash of the request payload. If there is
no payload, you must provide the hash of an empty string.
Each header name must:
You must include the host header (HTTP/1.1) or the :authority
header (HTTP/2), and any
x-amz-*
headers in the
signature. You can optionally include other standard headers in the
signature, such as content-type.
The
Lowercase()
and
Trim()
functions used in
this example are described in the preceding section.
The following is an example
CanonicalHeaders
string. The
header names are in lowercase and sorted.
host:s3.amazonaws.com x-amz-content-sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 x-amz-date:20130708T220855Z
Note
For the purpose of calculating an authorization signature, only the
host and any
x-amz-*
headers are required; however, in
order to prevent data tampering, you should consider including all the
headers in the signature calculation.
SignedHeaders
– An alphabetically sorted,
semicolon-separated list of lowercase request header names. The request
headers in the list are the same headers that you included in the
CanonicalHeaders
string. For example, for the previous
example, the value of
SignedHeaders
would be as
follows:
host;x-amz-content-sha256;x-amz-date
HashedPayload
– A string created using
the payload in the body of the HTTP request as input to a hash function.
This string uses lowercase hexadecimal characters.
Hex(SHA256Hash(
<payload>
)
If there is no payload in the request, you compute a hash of the empty string as follows:
Hex(SHA256Hash(""))
The hash returns the following value:
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
For example, when you upload an object by using a PUT request, you provide
object data in the body. When you retrieve an object by using a
GET
request, you compute the empty string hash.
Step 2: Create a hash of the canonical request
Create a hash (digest) of the canonical request using the same algorithm that you used to create the hash of the payload. The hash of the canonical request is a string of lowercase hexadecimal characters.
Step 3: Create a string to sign
Create a string by concatenating the following strings, separated by newline characters. Do not end this string with a newline character.
Algorithm
\nRequestDateTime
\nCredentialScope
\nHashedCanonicalRequest
Algorithm
– The algorithm used to create
the hash of the canonical request. For SHA-256, the algorithm is
AWS4-HMAC-SHA256
.
RequestDateTime
– The date and time used
in the credential scope. This value is the current UTC time in ISO 8601
format (for example,
20130524T000000Z
).
CredentialScope
– The credential scope.
This restricts the resulting signature to the specified Region and service.
The string has the following format:
YYYYMMDD
/
region
/
service
/aws4_request.
HashedCanonicalRequest
– The hash of the
canonical request. This value is calculated in Step 2.
The following is an example string to sign.
"AWS4-HMAC-SHA256" + "\n" + timeStampISO8601Format + "\n" +
<Scope>
+ "\n" + Hex(SHA256Hash(<CanonicalRequest>
))
Step 4: Calculate the signature
In AWS Signature Version 4, instead of using your AWS access keys to sign a request, you create a signing key that is scoped to a specific Region and service as the authentication information you'll add to your request.
DateKey = HMAC-SHA256("AWS4"+"
<SecretAccessKey>
", "<YYYYMMDD>
") DateRegionKey = HMAC-SHA256(<DateKey>
, "<aws-region>
") DateRegionServiceKey = HMAC-SHA256(<DateRegionKey>
, "<aws-service>
") SigningKey = HMAC-SHA256(<DateRegionServiceKey>
, "aws4_request")
For a list of Region strings, see Regional Endpoints in the AWS General Reference .
For each step, call the hash function with the required key and data. The result of each call to the hash function becomes the input for the next call to the hash function.
Required input
A string,
Key
, that contains your secret access key
A string,
Date
, that contains the date used in the credential
scope, in the format
YYYYMMDD
A string,
Region
, that contains the Region code (for example,
us-east-1
)
A string,
Service
, that contains the service code (for
example,
ec2
)
The string to sign that you created in the previous step.
To calculate the signature
-
Concatenate "AWS4" and the secret access key. Call the hash function with the concatenated string as the key and the date string as the data.
kDate = hash("AWS4" + Key, Date)
Call the hash function with the result of the previous call as the key and the Region string as the data.
kRegion = hash(kDate, Region)
Call the hash function with the result of the previous call as the key and the service string as the data.
kService = hash(kRegion, Service)
Call the hash function with the result of the previous call as the key and "aws4_request" as the data.
kSigning = hash(kService, "aws4_request")
Call the hash function with the result of the previous call as the key and the string to sign as the data. The result is the signature as a binary value.
signature = hash(kSigning,
string-to-sign
)Convert the signature from binary to hexadecimal representation, in lowercase characters.
Step 5: Add the signature to the request
Example: Authorization header
The following example shows an
Authorization
header for theDescribeInstances
action. For readability, this example is formatted with line breaks. In your code, this must be a continuous string. There is no comma between the algorithm andCredential
. However, the other elements must be separated by commas.Authorization: AWS4-HMAC-SHA256 Credential=AKIAIOSFODNN7EXAMPLE/20220830/us-east-1/ec2/aws4_request, SignedHeaders=host;x-amz-date, Signature=
calculated-signature
Example: Request with authentication parameters in the query string
The following example shows a query for the
DescribeInstances
action that includes the authentication information. For readability, this example is formatted with line breaks and is not URL encoded. In your code, the query string must be a continuous string that is URL encoded.https://ec2.amazonaws.com/? Action=DescribeInstances& Version=2016-11-15& X-Amz-Algorithm=AWS4-HMAC-SHA256& X-Amz-Credential=AKIAIOSFODNN7EXAMPLE/20220830/us-east-1/ec2/aws4_request& X-Amz-Date=20220830T123600Z& X-Amz-SignedHeaders=host;x-amz-date& X-Amz-Signature=
calculated-signature
Source code in the AWS SDKs
The AWS SDKs include source code on GitHub for signing AWS API requests. For code samples, see Example projects in AWS samples repository