Menu
Amazon DevPay
Getting Started Guide (API Version 2007-12-01)

Amazon S3 Requests

Your product will make calls to the Amazon Simple Storage Service on behalf of a customer. These calls are part of the overall process products follow to work with Amazon DevPay (for more information, see How a Product Works with DevPay).

This section describes how the product makes requests to Amazon S3 and uses the customer's credentials. For the Java, C#, and Ruby sample code, you can search for the differences between the original Amazon S3 library and the new DevPay version of the library to easily see what we've changed. The changes are in the AWSAuthConnection class. For information about where to get the original Amazon S3 library, see About the Sample Code.

Retrieve the Credentials

For desktop products, the credentials your product must retrieve are the customer's Access Key ID, Secret Access Key, and user token. For web products, the only credential is the customer's user token. Your product must retrieve and decode the credentials from their secure store location. How you store and retrieve them is up to you. For an example of one way to handle them, see the FileCredentialStore class in the security directory in the sample code package.

Add the Tokens to the Amazon S3 Request

Desktop products and web products must include the customer's user token in the Amazon S3 request. In addition, desktop products must include the product token (it's optional for web products that have a user token created after May 15, 2008). To include the tokens in the request, you add an x-amz-security-token header for each token. The following example shows a basic REST request (with the additional headers in red).

Date: Wed, 27 Jun 2007 03:40:41 GMT
Authorization: AWS 0PN6J17HBGXHT7JJ3X83:frJIUN8DYpKDtOLCwo//yllqDzgEXAMPLE=
x-amz-security-token: {UserToken}AAAHVXNlclRrbgfOpSykBAXO7g/zG....[long encoded token]...
			x-amz-security-token: {ProductToken}MIIBzTCCATagAwIBAgIGARB1qe....[long encoded token]...

An alternate method for passing both tokens is to add a single x-amz-security-token header with the tokens separated by a comma.

The following shows how to add the tokens to the request.

Java (Desktop Product)

For Java, make sure you add the two x-amz-security-token headers and not put them. Because the headers have the same name, if you put them, you'll overwrite the first with the second.

The following code snippet uses a single x-amz-security-token header with the values separated by a comma.

HttpURLConnection connection = ...;
connection.addRequestProperty("x-amz-security-token", userToken + "," + productToken);

C# (Desktop Product)

HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
req.Headers.Add("x-amz-security-token", userToken + "," + productToken);

C++ (Desktop Product)

The following code snippet shows the method in the C++ sample code that performs the initial step to get the headers added to the request (this code creates a map; see CppDevPaySample\s3\AWSAuthConnection.cpp). The line in red near the end of the snippet adds the user token and product token.

void AWSAuthConnection::addHeaders(REQUEST_TYPE method, int length, strmap &headers)
{
  string temp;
  //Add standard headers to the existing ones
  headers.insert(pair<string, string> (string("Host"), server_));
  temp.erase(); temp = utils_.getHTTPDate();
  headers.insert(pair<string, string> (string("Date"), temp));

  switch(method)
    {
    case PUT:
      if(length > 0)
	{
	  headers.insert(pair<string, string> (string("Content-Type"),string("binary")));
	}
      else
	{
	  headers.insert(pair<string, string> (string("Content-Type"), string("")));
	}
      headers.insert(pair<string, string> (string("Content-length"), utils_.itos(length)));
      headers.insert(pair<string, string> (string("Content-md5"), string("")));
      break;
    case GET:
    case DELETE:
      headers.insert(pair<string, string> (string("Content-Type"), string("")));
      headers.insert(pair<string, string> (string("Content-md5"), string("")));
      break;
    }
    if(!securityTokens_.empty())
    {
      set<string>::iterator i;
      for(i = securityTokens_.begin(); i != securityTokens_.end(); i++)
	{
	  headers.insert(pair<string, string> (utils_.AMAZON_SECURITY_HEADER, (*i)));
	}
    }
  return;

Ruby (Web Product)

The following code snippet uses a single x-amz-security-token header with the values separated by a comma.

http = Net::HTTP.new(server, port)
request = Net::HTTP::Get.new(path)
...
request['x-amz-security-token'] = product_token + "," + user_token
...
http.request(request)

Sign the Request

How you sign the Amazon S3 request for a DevPay product is essentially no different from how you do it for a product that doesn't use DevPay. You still sign the request with a Secret Access Key and include an Access Key ID in the Authorization header. For desktop products, you use the customer's Secret Access Key and Access Key ID. For web products, you use your Secret Access Key and Access Key ID.

When creating the string to sign, you still include any headers that start with x-amz, as discussed in the Amazon S3 documentation. The two new headers you added in the previous section start with x-amz, so they are included when the string to sign is created by your code. For information about how to sign an Amazon S3 request, go to the Amazon Simple Storage Service Developer Guide. Also refer to the basic Amazon S3 libraries (for information about their location, see About the Sample Code).

Java (Desktop Product)

The existing Java Amazon S3 library that we started with did not have to be modified because all the headers that begin with x-amz were already included in the string.

C# (Desktop Product)

The existing C# Amazon S3 library that we started with did not have to be modified because all the headers that begin with x-amz were already included in the string.

C++ (Desktop Product)

The C++ sample code handles the x-amz-security-token headers separately from the other headers that begin with x-amz. The following snippet is from CppDevPaySample\s3\Utils.cpp.

1AMAZON_SECURITY_HEADER = "x-amz-security-token";

2...

3if(temp.compare(0, AMAZON_SECURITY_HEADER.size(), AMAZON_SECURITY_HEADER) == 0)
4{
5    if(isSecurityHeaderAdded == false)
6    {
7        bool isFirst = true;
8	    ret = sortedheaders.equal_range(AMAZON_SECURITY_HEADER);
9	    result.append(AMAZON_SECURITY_HEADER);
10	    for(j = ret.first; j != ret.second; j++)
11	    {
12            result.append((isFirst == true) ? ":" : ",");
13            trimmedval.erase();
14            trimmedval = trimString((*j).second);
15            result.append(trimmedval);
16            if(isFirst == true)
17            isFirst = false;
18        }
19	    result.append("\n");
20	    isSecurityHeaderAdded = true;w
21    }
22}
23 LASTLINE

Ruby (Web Product)

The existing Ruby Amazon S3 library that we started with did not have to be modified because all the headers that begin with x-amz were already included in the string.