Menu
Amazon Web Services
General Reference (Version 1.0)

Task 1: Create a Canonical Request for Signature Version 4

To begin the signing process, create a string that includes information from your request in a standardized (canonical) format. This ensures that when AWS receives the request, it can calculate the same signature that you calculated.

Follow the steps here to create a canonical version of the request. Otherwise, your version and the version calculated by AWS won't match, and the request will be denied.

The following example shows the pseudocode to create a canonical request.

Canonical request pseudocode

Copy
CanonicalRequest = HTTPRequestMethod + '\n' + CanonicalURI + '\n' + CanonicalQueryString + '\n' + CanonicalHeaders + '\n' + SignedHeaders + '\n' + HexEncode(Hash(RequestPayload))

In this pseudocode, Hash represents a function that produces a message digest, typically SHA-256. (Later in the process, you specify which hashing algorithm you're using.) HexEncode represents a function that returns the base-16 encoding of the digest in lowercase characters. For example, HexEncode("m") returns the value 6d rather than 6D. Each input byte must be represented as exactly two hexadecimal characters.

Signature Version 4 does not require that you use a particular character encoding to encode the canonical request. However, some AWS services might require a specific encoding. For more information, consult the documentation for that service.

The following examples show how to construct the canonical form of a request to IAM. The original request might look like this as it is sent from the client to AWS, except that this example does not include the signing information yet.

Example request

Copy
GET https://iam.amazonaws.com/?Action=ListUsers&Version=2010-05-08 HTTP/1.1 Host: iam.amazonaws.com Content-Type: application/x-www-form-urlencoded; charset=utf-8 X-Amz-Date: 20150830T123600Z

The preceding example request is a GET request (method) that makes a ListUsers API (action) call to AWS Identity and Access Management (host). This action takes the Version parameter.

To create a canonical request, concatenate the following components from each step into a single string:

  1. Start with the HTTP request method (GET, PUT, POST, etc.), followed by a newline character.

    Example request method

    Copy
    GET
  2. Add the canonical URI parameter, followed by a newline character. The canonical URI is the URI-encoded version of the absolute path component of the URI, which is everything in the URI from the HTTP host to the question mark character ("?") that begins the query string parameters (if any).

    Normalize URI paths according to RFC 3986. Remove redundant and relative path components. Each path segment must be URI-encoded.

    Example canonical URI with encoding

    Copy
    /documents%20and%20settings/

    Note

    In exception to this, you do not normalize URI paths for requests to Amazon S3. For example, if you have a bucket with an object named my-object//example//photo.user, use that path. Normalizing the path to my-object/example/photo.user will cause the request to fail. For more information, see Task 1: Create a Canonical Request in the Amazon Simple Storage Service API Reference.

    If the absolute path is empty, use a forward slash (/). In the example IAM request, nothing follows the host in the URI, so the absolute path is empty.

    Example canonical URI

    Copy
    /
  3. Add the canonical query string, followed by a newline character. If the request does not include a query string, use an empty string (essentially, a blank line). The example request has the following query string.

    Example canonical query string

    Copy
    Action=ListUsers&Version=2010-05-08

    To construct the canonical query string, complete the following steps:

    1. Sort the parameter names by character code point in ascending order. For example, a parameter name that begins with the uppercase letter F precedes a parameter name that begins with a lowercase letter b.

    2. URI-encode each parameter name and value according to the following rules:

      • Do not URI-encode any of the unreserved characters that RFC 3986 defines: A-Z, a-z, 0-9, hyphen ( - ), underscore ( _ ), period ( . ), and tilde ( ~ ).

      • Percent-encode all other characters with %XY, where X and Y are hexadecimal characters (0-9 and uppercase A-F). For example, the space character must be encoded as %20 (not using '+', as some encoding schemes do) and extended UTF-8 characters must be in the form %XY%ZA%BC.

    3. Build the canonical query string by starting with the first parameter name in the sorted list.

    4. For each parameter, append the URI-encoded parameter name, followed by the equals sign character (=), followed by the URI-encoded parameter value. Use an empty string for parameters that have no value.

    5. Append the ampersand character (&) after each parameter value, except for the last value in the list.

    One option for the query API is to put all request parameters in the query string. For example, you can do this for Amazon S3 to create a presigned URL. In that case, the canonical query string must include not only parameters for the request, but also the parameters used as part of the signing process—the hashing algorithm, credential scope, date, and signed headers parameters.

    The following example shows a query string that includes authentication information. The example is formatted with line breaks for readability, but the canonical query string must be one continuous line of text in your code.

    Example authentication parameters in a query string

    Copy
    Action=ListUsers& Version=2010-05-08& X-Amz-Algorithm=AWS4-HMAC-SHA256& X-Amz-Credential=AKIDEXAMPLE%2F20150830%2Fus-east-1%2Fiam%2Faws4_request& X-Amz-Date=20150830T123600Z& X-Amz-SignedHeaders=content-type%3Bhost%3Bx-amz-date

    For more information about authentication parameters, see Task 2: Create a String to Sign for Signature Version 4.

    Note

    You can use temporary security credentials provided by the AWS Security Token Service (AWS STS) to sign a request. The process is the same as using long-term credentials, but when you add signing information to the query string you must add an additional query parameter for the security token. The parameter name is X-Amz-Security-Token, and the parameter's value is the URI-encoded session token (the string you received from AWS STS when you obtained temporary security credentials).

    For some services, you must include the X-Amz-Security-Token query parameter in the canonical (signed) query string. For other services, you add the X-Amz-Security-Token parameter at the end, after you calculate the signature. For details, see the API reference documentation for that service.

  4. Add the canonical headers, followed by a newline character. The canonical headers consist of a list of all the HTTP headers that you are including with the signed request.

    At a minimum, you must include the host header. Standard headers like content-type are optional. Different services might require other headers.

    Example canonical headers

    Copy
    content-type:application/x-www-form-urlencoded; charset=utf-8\n host:iam.amazonaws.com\n x-amz-date:20150830T123600Z\n

    To create the canonical headers list, convert all header names to lowercase and remove leading spaces and trailing spaces. Convert sequential spaces in the header value to a single space.

    The following pseudocode describes how to construct the canonical list of headers:

    Copy
    CanonicalHeaders = CanonicalHeadersEntry0 + CanonicalHeadersEntry1 + ... + CanonicalHeadersEntryN CanonicalHeadersEntry = Lowercase(HeaderName) + ':' + Trimall(HeaderValue) + '\n'

    Lowercase represents a function that converts all characters to lowercase. The Trimall function removes excess white space before and after values, and converts sequential spaces to a single space.

    Build the canonical headers list by sorting the (lowercase) headers by character code and then iterating through the header names. Construct each header according to the following rules:

    • Append the lowercase header name followed by a colon.

    • Append a comma-separated list of values for that header. Do not sort the values in headers that have multiple values.

    • Append a new line ('\n').

    The following examples compare a more complex set of headers with their canonical form:

    Original headers

    Copy
    Host:iam.amazonaws.com\n Content-Type:application/x-www-form-urlencoded; charset=utf-8\n My-header1:    a   b   c \n X-Amz-Date:20150830T123600Z\n My-Header2:    "a   b   c" \n

    Canonical form

    Copy
    content-type:application/x-www-form-urlencoded; charset=utf-8\n host:iam.amazonaws.com\n my-header1:a b c\n my-header2:"a b c"\n x-amz-date:20150830T123600Z\n

    Note

    Each header is followed by a newline character, meaning the complete list ends with a newline character.

    In the canonical form, the following changes were made:

    • The header names were converted to lowercase characters.

    • The headers were sorted by character code.

    • Leading and trailing spaces were removed from the my-header1 and my-header2 values.

    • Sequential spaces in a b c were converted to a single space for the my-header1 and my-header2 values.

    Note

    You can use temporary security credentials provided by the AWS Security Token Service (AWS STS) to sign a request. The process is the same as using long-term credentials, but when you include signing information in the Authorization header you must add an additional HTTP header for the security token. The header name is X-Amz-Security-Token, and the header's value is the session token (the string you received from AWS STS when you obtained temporary security credentials).

  5. Add the signed headers, followed by a newline character. This value is the list of headers that you included in the canonical headers. By adding this list of headers, you tell AWS which headers in the request are part of the signing process and which ones AWS can ignore (for example, any additional headers added by a proxy) for purposes of validating the request.

    The host header must be included as a signed header. If you include a date or x-amz-date header, you must also include that header in the list of signed headers.

    To create the signed headers list, convert all header names to lowercase, sort them by character code, and use a semicolon to separate the header names. The following pseudocode describes how to construct a list of signed headers. Lowercase represents a function that converts all characters to lowercase.

    Copy
    SignedHeaders = Lowercase(HeaderName0) + ';' + Lowercase(HeaderName1) + ";" + ... + Lowercase(HeaderNameN)

    Build the signed headers list by iterating through the collection of header names, sorted by lowercase character code. For each header name except the last, append a semicolon (';') to the header name to separate it from the following header name.

    Example signed headers

    Copy
    content-type;host;x-amz-date\n
  6. Use a hash (digest) function like SHA256 to create a hashed value from the payload in the body of the HTTP or HTTPS request. Signature Version 4 does not require that you use a particular character encoding to encode text in the payload. However, some AWS services might require a specific encoding. For more information, consult the documentation for that service.

    Structure of payload

    Copy
    HashedPayload = Lowercase(HexEncode(Hash(requestPayload)))

    When you create the string to sign, you specify the signing algorithm that you used to hash the payload. For example, if you used SHA256, you will specify AWS4-HMAC-SHA256 as the signing algorithm. The hashed payload must be represented as a lowercase hexadecimal string.

    If the payload is empty, use an empty string as the input to the hash function. In the IAM example, the payload is empty.

    Example hashed payload (empty string)

    Copy
    e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
  7. To construct the finished canonical request, combine all the components from each step as a single string. As noted, each component ends with a newline character. If you follow the canonical request pseudocode explained earlier, the resulting canonical request is shown in the following example.

    Example canonical request

    Copy
    GET / Action=ListUsers&Version=2010-05-08 content-type:application/x-www-form-urlencoded; charset=utf-8 host:iam.amazonaws.com x-amz-date:20150830T123600Z content-type;host;x-amz-date e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
  8. Create a digest (hash) of the canonical request with the same algorithm that you used to hash the payload.

    Note

    Signature Version 4 does not require that you use a particular character encoding to encode the canonical request before calculating the digest. However, some AWS services might require a specific encoding. For more information, consult the documentation for that service.

    The hashed canonical request must be represented as a string of lowercase hexademical characters. The following example shows the result of using SHA-256 to hash the example canonical request.

    Example hashed canonical request

    Copy
    f536975d06c0309214f805bb90ccff089219ecd68b2577efef23edd43b7e1a59

    You include the hashed canonical request as part of the string to sign in Task 2: Create a String to Sign for Signature Version 4.