Menu
Amazon Web Services
General Reference (Version 1.0)

Signing AWS Requests with Signature Version 4

This section explains how to create a signature and add it to a request.

What Signing Looks Like in a Request

The following example shows what an HTTPS request might look like as it is sent from your client to AWS, without any signing information.

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

After you complete the signing tasks, you add the authentication information to the request. You can add the authentication information in two ways:

Authorization header

You can add the authentication information to the request with an Authorization header. Although the HTTP header is named Authorization, the signing information is actually used for authentication to establish who the request came from.

The Authorization header includes the following information:

  • Algorithm you used for signing (AWS4-HMAC-SHA256)

  • Credential scope (with your access key ID)

  • List of signed headers

  • Calculated signature. The signature is based on your request information, and you use your AWS secret access key to produce the signature. The signature confirms your identity to AWS.

The following example shows what the preceding request might look like after you've created the signing information and added it to the request in the Authorization header.

Copy
GET https://iam.amazonaws.com/?Action=ListUsers&Version=2010-05-08 HTTP/1.1 Authorization: AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/iam/aws4_request, SignedHeaders=content-type;host;x-amz-date, Signature=5d672d79c15b13162d9279b0855cfba6789a8edb4c82c400e06b5924a6f2b5d7 content-type: application/x-www-form-urlencoded; charset=utf-8 host: iam.amazonaws.com x-amz-date: 20150830T123600Z

Query string

As an alternative to adding authentication information with an HTTP request header, you can include it in the query string. The query string contains everything that is part of the request, including the name and parameters for the action, the date, and the authentication information.

The following example shows how you might construct a GET request with the action and authentication information in the query string.

Copy
GET https://iam.amazonaws.com?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-Expires=60&X-Amz-SignedHeaders=content-type%3Bhost&X-Amz-Signature=37ac2f4fde00b0ac9bd9eadeb459b1bbee224158d66e7ae5fcadb70b2d181d02 HTTP/1.1 content-type: application/x-www-form-urlencoded; charset=utf-8 host: iam.amazonaws.com

GET and POST Requests in the Query API

The query API that many AWS services support lets you make requests using either HTTP GET or POST. (In the query API, you can use GET even if you're making requests that change state; that is, the query API is not inherently RESTful.) Because GET requests pass parameters on the query string, they are limited to the maximum length of a URL. If a request includes a large payload (for example, you might upload a large IAM policy or send many parameters in JSON format for a DynamoDB request), you generally use a POST request.

The signing process is the same for both types of requests.

Summary of Signing Steps

To create a signed request, complete the following:

Note

The AWS SDKs handle the signature calculation process for you, so you do not have to manually complete the signing process. For more information, see Tools for Amazon Web Services.

The following additional resources illustrate aspects of the signing process:

  • Examples of How to Derive a Signing Key for Signature Version 4. This page shows how to derive a signing key using Java, C#, Python, Ruby, and JavaScript.

  • Examples of the Complete Version 4 Signing Process (Python). This set of programs in Python provide complete examples of the signing process. The examples show signing with a POST request, with a GET request that has signing information in a request header, and with a GET request that has signing information in the query string.

  • Signature Version 4 Test Suite. This downloadable package contains a collection of examples that include signature information for various steps in the signing process. You can use these examples to verify that your signing code is producing the correct results at each step of the process.

On this page:

  • What Signing Looks Like in a Request
  • GET and POST Requests in the Query API
  • Summary of Signing Steps
  • Task 1: Create a Canonical Request for Signature Version 4Task 1: Create a Canonical Request Walk through the steps to 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 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 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: Start with the HTTP request method (GET, PUT, POST, etc.), followed by a newline character. Example request method GET 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 /documents%20and%20settings/ 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 / 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 Action=ListUsers&Version=2010-05-08 To construct the canonical query string, complete the following steps: 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. 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. Build the canonical query string by starting with the first parameter name in the sorted list. 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. 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 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 . 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. 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 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: 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 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 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 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. 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). 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. 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 content-type;host;x-amz-date\n 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 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) e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 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 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 Create a digest (hash) of the canonical request with the same algorithm that you used to hash the payload. 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 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 4Task 2: Create a String to Sign Walk through the steps to create a string to sign for Signature Version 4. The string to sign includes meta information about your request and about the canonical request that you created in . You will use the string to sign and a derived signing key that you create later as inputs to calculate the request signature in . To create the string to sign, concatenate the algorithm, date and time, credential scope, and digest of the canonical request, as shown in the following pseudocode: Structure of string to sign StringToSign = Algorithm + \n + RequestDateTime + \n + CredentialScope + \n + HashedCanonicalRequest The following example shows how to construct the string to sign with the same request from Task 1: Create A Canonical Request. Example HTTPS request 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 To create the string to sign Start with the algorithm designation, followed by a newline character. This value is the hashing algorithm that you use to calculate the digests in the canonical request. For SHA256, AWS4-HMAC-SHA256 is the algorithm. AWS4-HMAC-SHA256\n Append the request date value, followed by a newline character. The date is specified with ISO8601 basic format in the x-amz-date header in the format YYYYMMDD'T'HHMMSS'Z'. This value must match the value you used in any previous steps. 20150830T123600Z\n Append the credential scope value, followed by a newline character. This value is a string that includes the date, the region you are targeting, the service you are requesting, and a termination string ("aws4_request") in lowercase characters. The region and service name strings must be UTF-8 encoded. 20150830/us-east-1/iam/aws4_request\n The date must be in the YYYYMMDD format. Note that the date does not include a time value. Verify that the region you specify is the region that you are sending the request to. See . Append the hash of the canonical request that you created in . This value is not followed by a newline character. The hashed canonical request must be lowercase base-16 encoded, as defined by Section 8 of RFC 4648. f536975d06c0309214f805bb90ccff089219ecd68b2577efef23edd43b7e1a59 The following string to sign is a request to IAM on August 30, 2015. Example string to sign AWS4-HMAC-SHA256 20150830T123600Z 20150830/us-east-1/iam/aws4_request f536975d06c0309214f805bb90ccff089219ecd68b2577efef23edd43b7e1a59 Task 3: Calculate the Signature for AWS Signature Version 4Task 3: Calculate the Signature Calculate the signature for AWS Signature Version 4. Before you calculate a signature, you derive a signing key from your AWS secret access key. Because the derived signing key is specific to the date, service, and region, it offers a greater degree of protection. You don't just use your secret access key to sign the request. You then use the signing key and the string to sign that you created in as the inputs to a keyed hash function. The hex-encoded result from the keyed hash function is the signature. Signature Version 4 does not require that you use a particular character encoding to encode the string to sign. However, some AWS services might require a specific encoding. For more information, consult the documentation for that service. To calculate a signature Derive your signing key. To do this, use your secret access key to create a series of hash-based message authentication codes (HMACs). This is shown in the following pseudocode, where HMAC(key, data) represents an HMAC-SHA256 function that returns output in binary format. The result of each hash function becomes input for the next one. Pseudocode for deriving a signing key kSecret = your secret access key kDate = HMAC("AWS4" + kSecret, Date) kRegion = HMAC(kDate, Region) kService = HMAC(kRegion, Service) kSigning = HMAC(kService, "aws4_request") Note that the date used in the hashing process is in the format YYYYMMDD (for example, 20150830), and does not include the time. Make sure you specify the HMAC parameters in the correct order for the programming language you are using. This example shows the key as the first parameter and the data (message) as the second parameter, but the function that you use might specify the key and data in a different order. Use the digest (binary format) for the key derivation. Most languages have functions to compute either a binary format hash, commonly called a digest, or a hex-encoded hash, called a hexdigest. The key derivation requires that you use a binary-formatted digest. The following example show the inputs to derive a signing key and the resulting output, where kSecret = wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY. The example uses the same parameters from the request in Task 1 and Task 2 (a request to IAM in the us-east-1 region on August 30, 2015). Example inputs HMAC(HMAC(HMAC(HMAC("AWS4" + kSecret,"20150830"),"us-east-1"),"iam"),"aws4_request") The following example shows the derived signing key that results from this sequence of HMAC hash operations. This shows the hexadecimal representation of each byte in the binary signing key. Example signing key c4afb1cc5771d871763a393e44b703571b55cc28424d1a5e86da6ed3c154a4b9 For more information about how to derive a signing key in different programming languages, see . Calculate the signature. To do this, use the signing key that you derived and the string to sign as inputs to the keyed hash function. After you calculate the signature, convert the binary value to a hexadecimal representation. The following pseudocode shows how to calculate the signature. signature = HexEncode(HMAC(derived signing key, string to sign)) The following example shows the resulting signature if you use the same signing key and the string to sign from Task 2: Example signature 5d672d79c15b13162d9279b0855cfba6789a8edb4c82c400e06b5924a6f2b5d7 Task 4: Add the Signing Information to the Request Add a signature to Signature Version 4 request. After you calculate the signature, you add it to the request. You can add the signing information to a request in one of two ways: An HTTP header named Authorization The query string You cannot pass signing information in both the Authorization header and the query string. 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 requires an additional HTTP header or query string parameter for the security token. The name of the header or query string parameter is X-Amz-Security-Token, and the value is the session token (the string you received from AWS STS when you obtained temporary security credentials). When you add the X-Amz-Security-Token parameter to the query string, some services require that you include this parameter in the canonical (signed) request. For other services, you add this parameter at the end, after you calculate the signature. For details, see the API reference documentation for that service.
  • Adding Signing Information to the Authorization Header
  • Adding Signing Information to the Query String