You must sign all HTTP and HTTPS API requests to ensure security. Alibaba Cloud uses the request signature to authenticate the identity of the API caller. Message Queue for Apache Kafka implements symmetric encryption by using an AccessKey pair to authenticate the identity of the API caller.

An AccessKey pair is an identity credential that is used when you call an API. This credential is similar to the username and password that you use to log on to the Message Queue for Apache Kafka console. An AccessKey pair consists of an AccessKey ID and an AccessKey secret. The AccessKey ID is used to authenticate the identity of the user, and the AccessKey secret is used to encrypt and authenticate the signature string. You must keep your AccessKey secret strictly confidential.

Note Message Queue for Apache Kafka provides SDKs in multiple programming languages to automatically calculate the signature string. For more information, see Download SDK.

Step 1: Create a canonicalized query string

  1. Arrange the request parameters. Arrange the request parameters in alphabetical order. The request parameters include common request parameters and operation-specific parameters except Signature.
  2. Encode the request parameters and their values in UTF-8 based on RFC 3986. The following rules apply in the encoding process:
    • Uppercase letters, lowercase letters, digits, and specific special characters such as hyphens (-), underscores (_), periods (.), and tildes (~) do not need to be encoded.
    • Other characters must be percent encoded in the %XY format. XY represents the ASCII code of the characters in hexadecimal notation. For example, double quotation marks (") are encoded as %22.
    • Extended UTF-8 characters are encoded in the %XY%ZA… format.
    • Spaces must be encoded as %20. Do not encode spaces as plus signs (+).

      The preceding encoding method is similar to but slightly different from the application/x-www-form-urlencoded MIME-type encoding algorithm.

      If you use java.net.URLEncoder in the Java standard library, use percentEncode to encode request parameters and their values. In the encoded query string, replace the plus sign (+) with %20, the asterisk (*) with %2A, and %7E with a tilde (~). This way, you can obtain an encoded string that matches the preceding encoding rules. This process is shown in the following sample code:

      private static final String ENCODING = "UTF-8";
      private static String percentEncode(String value) throws UnsupportedEncodingException {
      return value != null ? URLEncoder.encode(value, ENCODING).replace("+", "%20").replace("*", "%2A").replace("%7E", "~") : null;
      }                                
  3. Use an equal sign (=) to connect each encoded request parameter and its value.
  4. Use an ampersand (&) to connect the encoded request parameters. These parameters must be arranged in the same order as those in Step 1.

After you complete this process, you can obtain a canonicalized query string (CanonicalizedQueryString) whose structure complies with the HTTP request structure. For more information, see Request syntax.

Step 2: Create a string-to-sign

  1. Create a string-to-sign. You can also use percentEncode to encode the canonicalized query string that is created in the Step 1. Comply with the following rules to create a string-to-sign:
    StringToSign=
    HTTPMethod + "&" + //HTTPMethod: Specify the HTTP method used to make the request, such as POST. percentEncode("/") + "&" + //percentEncode("/"): Encode backslashes (/) as %2F. percentEncode(CanonicalizedQueryString) // Encode the canonicalized query string created in Step 1. 
  2. Calculate the hash-based message authentication code (HMAC) value of the string-to-sign, as defined in RFC 2104. Use the Secure Hash Algorithm 1 (SHA-1) algorithm to calculate the HMAC value. The examples in this topic use the Java Base64 encoding method.
    Signature = Base64( HMAC-SHA1( AccessSecret, UTF-8-Encoding-Of(StringToSign) ) )                        
    Note When you calculate the signature, the key value specified by RFC 2104 is your AccessKey secret with an ampersand (&) appended to it. The ASCII value of an ampersand (&) is 38.
  3. Encode the Signature parameter based on RFC 3986 and add it to the canonicalized query string.

Example 1: Concatenate parameters

For example, you want to call the GetInstanceList operation to query instances. In this example, the value of AccessKeyID is testid and the value of AccessKeySecret is testsecret.

  1. Construct a canonicalized query string.
    http://alikafka.%s.aliyuncs.com/?Timestamp=2016-02-23T12:46:24Z&Format=XML&AccessKeyId=testid&Action=GetInstanceList&SignatureMethod=HMAC-SHA1&SignatureNonce=3ee8c1b8-83d3-44af-a94f-4e0ad82fd6cf&Version=2014-05-26&SignatureVersion=1.0                    
  2. Create a string-to-sign.
    POST&%2F&AccessKeyId%3Dtestid&Action%3DGetInstanceList&Format%3DXML&SignatureMethod%3DHMAC-SHA1&SignatureNonce%3D3ee8c1b8-83d3-44af-a94f-4e0ad82fd6cf&SignatureVersion%3D1.0&Timestamp%3D2016-02-23T12%253A46%253A24Z&Version%3D2014-05-26                    
  3. Calculate the signature. The key value used for calculation is testsecret& because AccessKeySecret is set to testsecret. The calculated signature is OLeaidS1JvxuMvnyHOwuJ+uX5qY=. This example uses the Java Base64 encoding method.
    Signature = Base64( HMAC-SHA1( AccessSecret, UTF-8-Encoding-Of(StringToSign) ) )                    
  4. Add Signature=OLeaidS1JvxuMvnyHOwuJ%2BuX5qY%3D to the URL in Step 1.
    http://alikafka.%s.aliyuncs.com/?SignatureVersion=1.0&Action=GetInstanceList&Format=JSON&SignatureNonce=3ee8c1b8-83d3-44af-a94f-4e0ad82fd6cf&Version=2014-05-26&AccessKeyId=testid&Signature=OLeaidS1JvxuMvnyHOwuJ%2BuX5qY%3D&SignatureMethod=HMAC-SHA1&Timestamp=2016-02-23T12%253A46%253A24Z                    

You can use the new URL in a browser, in curl, or in wget to initiate an HTTP request that calls the GetInstanceList operation.

Example 2: Use the standard library of a programming language

For example, you want to call the GetInstanceList operation to query instances. In this example, the value of AccessKeyID is testid and the value of AccessKeySecret is testsecret. All request parameters are placed in a Java Map<String, String> object.

  1. Predefine the encoding method.
    private static final String ENCODING = "UTF-8";
    private static String percentEncode(String value) throws UnsupportedEncodingException {
    return value != null ? URLEncoder.encode(value, ENCODING).replace("+", "%20").replace("*", "%2A").replace("%7E", "~") : null;
    }                    
  2. Predefine the time format for the Timestamp parameter. The value of the Timestamp parameter must conform to the ISO 8601 standard. The time must be in UTC+0.
    private static final String ISO8601_DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss'Z'";
    private static String formatIso8601Date(Date date) {
    SimpleDateFormat df = new SimpleDateFormat(ISO8601_DATE_FORMAT);
    df.setTimeZone(new SimpleTimeZone(0, "GMT"));
    return df.format(date);
    }                    
  3. Construct the canonicalized query string.
    final String HTTP_METHOD = "POST";
    Map parameters = new HashMap();
    // Specify request parameters. 
    parameters.put("Action", "GetInstanceList");
    parameters.put("Version", "2014-05-26");
    parameters.put("AccessKeyId", "testid");
    parameters.put("Timestamp", formatIso8601Date(new Date()));
    parameters.put("SignatureMethod", "HMAC-SHA1");
    parameters.put("SignatureVersion", "1.0");
    parameters.put("SignatureNonce", UUID.randomUUID().toString());
    parameters.put("Format", "JSON");
    // Arrange the request parameters. 
    String[] sortedKeys = parameters.keySet().toArray(new String[]{});
    Arrays.sort(sortedKeys);
    final String SEPARATOR = "&";
    // Create a string-to-sign. 
    StringBuilder stringToSign = new StringBuilder();
    stringToSign.append(HTTP_METHOD).append(SEPARATOR);
    stringToSign.append(percentEncode("/")).append(SEPARATOR);
    StringBuilder canonicalizedQueryString = new StringBuilder();
    for(String key : sortedKeys) {
    // Encode the key and value. 
    canonicalizedQueryString.append("&")
    .append(percentEncode(key)).append("=")
    .append(percentEncode(parameters.get(key)));
    }
    // Encode the canonicalized query string. 
    stringToSign.append(percentEncode(
    canonicalizedQueryString.toString().substring(1)));                 
  4. Calculate the signature. The key value used for calculation is testsecret& because AccessKeySecret is set to testsecret. The calculated signature is OLeaidS1JvxuMvnyHOwuJ%2BuX5qY%3D=.
    // The following sample code demonstrates how to calculate the signature. 
    final String ALGORITHM = "HmacSHA1";
    final String ENCODING = "UTF-8";
    key = "testsecret&";
    Mac mac = Mac.getInstance(ALGORITHM);
    mac.init(new SecretKeySpec(key.getBytes(ENCODING), ALGORITHM));
    byte[] signData = mac.doFinal(stringToSign.getBytes(ENCODING));
    String signature = new String(Base64.encodeBase64(signData));