Signature

Last updated: 2019-08-21 15:34:00

TencentCloud API authenticates each access request, i.e. each request needs to include signature information (Signature) in the common request parameters to verify the identity of the requester. The Signature is generated by the security credentials which include SecretId and SecretKey. If you don't have the security credentials yet, please go to the TencentCloud API Key page to apply; otherwise, you cannot call the TencentCloud API.

1. Applying for Security Credentials

Before using the TencentCloud API for the first time, go to the TencentCloud API Key page to apply for security credentials. Security credentials include SecretId and SecretKey:

  • SecretId is used to identify the API caller.
  • SecretKey is used to encrypt the signature string and verify it on the server.
  • You must keep your security credentials private and avoid disclosure.

You can apply for the security credentials in the following steps:

  1. Log in to Tencent Cloud Console.
  2. Go to the TencentCloud API Key page
  3. On the TencentCloud API Key page, click New to create a pair of SecretId/SecretKey

Note: A developer account can have up to two pairs of SecretId/SecretKey.

2. Generating Signature String

After obtaining the security credentials (SecretId and SecretKey), you can generate a signature string. Below describes how to generate the signature string in details:

Assume that the SecretId and SecretKey are:

  • SecretId: AKIDz8krbsJ5yKBZQpn74WFkmLPx3EXAMPLE
  • SecretKey: Gu5t9xGARNpq86cd98joQYCN3EXAMPLE

Note: This is just a sample here. For actual operations, use your real SecretId and SecretKey!

Take the Cloud Virtual Machine's request to view the instance list (DescribeInstances) as an example. When you invoke this API, the request parameters may be as follows:

Parameter name English Parameter value
Action Method name DescribeInstances
SecretId Key ID AKIDz8krbsJ5yKBZQpn74WFkmLPx3EXAMPLE
Timestamp Current timestamp 1465185768
Nonce Random positive integer 11886
Region Region where the instance is located ap-guangzhou
InstanceIds.0 ID of the instance to query ins-09dx96dg
Offset Offset 0
Limit Allowed maximum output 20
Version API version number 2017-03-12

2.1. Sorting Parameters

First, sort all request parameters by parameter name in ascending lexicographical order (ASCII code). Note: 1) Sort the parameters only by parameter name and keep the parameter values corresponding which don't participate in the ranking; 2) Rank the parameters by ASCII code, for example, InstanceIds.2 should be ranked after InstanceIds.12 (not by alphabet nor by value). You can do this with the aid of related sorting functions in the programming language, such as the ksort function in PHP. The sorting results of the sample parameters above are as follows:

{
    'Action' : 'DescribeInstances',
    'InstanceIds.0' : 'ins-09dx96dg',
    'Limit' : 20,
    'Nonce' : 11886,
    'Offset' : 0,
    'Region' : 'ap-guangzhou',
    'SecretId' : 'AKIDz8krbsJ5yKBZQpn74WFkmLPx3EXAMPLE',
    'Timestamp' : 1465185768,
    'Version': '2017-03-12',
}

When developing in another programming language, you can sort these sample parameters and it would work as long as you get the same results.

2.2. Splicing a Request String

This step generates a request string. Format the request parameters sorted in the previous step into the form of "parameter name"="parameter value". For example, for the Action parameter, its parameter name is "Action" and its parameter value is "DescribeInstances", so it will become Action=DescribeInstances after formatted. Note: The "parameter value" is the original value but not the value after URL encoding.

Then, splice together the formatted parameters with "&". The resulting request string is as follows:

Action=DescribeInstances&InstanceIds.0=ins-09dx96dg&Limit=20&Nonce=11886&Offset=0&Region=ap-guangzhou&SecretId=AKIDz8krbsJ5yKBZQpn74WFkmLPx3EXAMPLE&Timestamp=1465185768&Version=2017-03-12

2.3. Splicing a Signature Original String

This step generates a signature original string, which consists of the following parameters:

  1. Request method: POST and GET modes are supported, and GET is used here for the request. Please note that the method name should be in all capital letters.
  2. Request server: The domain name of the request to view the list of instances (DescribeInstances) is cvm.tencentcloudapi.com. The actual request domain name varies for different modules to which the API belongs. For details, see the instructions of the specific API.
  3. Request path: The request path in the current version of TencentCloud API is fixed to /.
  4. Request string: That is the request string generated in the previous step.

The splicing rule of the signature original string is: Request method + request host + request path + ? + request string

The splicing result of the sample is:

GETcvm.tencentcloudapi.com/?Action=DescribeInstances&InstanceIds.0=ins-09dx96dg&Limit=20&Nonce=11886&Offset=0&Region=ap-guangzhou&SecretId=AKIDz8krbsJ5yKBZQpn74WFkmLPx3EXAMPLE&Timestamp=1465185768&Version=2017-03-12

2.4. Generating a Signature String

This step generates a signature string. First, use the HMAC-SHA1 algorithm to sign the signature original string obtained in the previous step, and then encode the generated signature string using Base64 to obtain the final signature string.

The specific code is as follows with the PHP language as an example:

$secretKey = 'Gu5t9xGARNpq86cd98joQYCN3EXAMPLE';
$srcStr = 'GETcvm.tencentcloudapi.com/?Action=DescribeInstances&InstanceIds.0=ins-09dx96dg&Limit=20&Nonce=11886&Offset=0&Region=ap-guangzhou&SecretId=AKIDz8krbsJ5yKBZQpn74WFkmLPx3EXAMPLE&Timestamp=1465185768&Version=2017-03-12';
$signStr = base64_encode(hash_hmac('sha1', $srcStr, $secretKey, true));
echo $signStr;

The final signature string is:

EliP9YW3pW28FpsEdkXt/+WcGeI=

When developing in another programming language, you can sign and verify the original in the sample above and it would work as long as you get the same results.

3. Encoding Signature String

The generated signature string cannot be directly used as a request parameter and needs to be URL encoded.

For example, if the signature string generated in the previous step is EliP9YW3pW28FpsEdkXt/+WcGeI=, the final signature string request parameter (Signature) is EliP9YW3pW28FpsEdkXt%2f%2bWcGeI%3d, which will be used to generate the final request URL.

Note: If your request method is GET, or the request method is POST and the Content-Type is application/x-www-form-urlencoded, then all the request parameter values need to be URL encoded (except the parameter key and the symbol of =) when sending the request. Non-ASCII characters need to be encoded with UTF-8 before URL encoding.

Note: The HTTP libraries of some programming languages automatically URL encode all parameters, in which case there is no need to URL encode the signature string; otherwise, two rounds of URL encoding will cause the signature to fail.

Note: Other parameter values also need to be encoded using RFC 3986. Use %XY for percent-encoding of special characters such as Chinese characters, where "X" and "Y" are hexadecimal characters (0-9 and uppercase A-F), and using lowercase will cause an error.

4. Signature Failure

The following error codes for signature failure exist based on the actual conditions. Please cope with the errors accordingly.

Error code Error description
AuthFailure.SignatureExpire Signature expired
AuthFailure.SecretIdNotFound The key does not exist
AuthFailure.SignatureFailure Signature error
AuthFailure.TokenFailure Token error
AuthFailure.InvalidSecretId Invalid key (not TencentCloud API key type)

5. Signature Demo

When calling API 3.0, it is recommended to use the corresponding Tencent Cloud SDK 3.0 which encapsulates the signature process, enabling you to focus on only the specific APIs provided by the product when developing. See SDK Center for more information. Currently, the following programming languages are supported:

In order to explain the signing process more clearly, the process described above is implemented below with a real-world programming language as an example. The request domain name, called API and parameter values in the sample are used here. The code here is only for explaining the signature process and not universal. For actual development, please use the SDK as much as possible.

The final output URL might be: https://cvm.tencentcloudapi.com/?Action=DescribeInstances&InstanceIds.0=ins-09dx96dg&Limit=20&Nonce=11886&Offset=0&Region=ap-guangzhou&SecretId=AKIDz8krbsJ5yKBZQpn74WFkmLPx3EXAMPLE&Signature=EliP9YW3pW28FpsEdkXt%2F%2BWcGeI%3D&Timestamp=1465185768&Version=2017-03-12

Note: The key in the example is fictitious, and the timestamp is not the current time of the system, so if this URL is opened in the browser or called using commands such as curl, an authentication error will be returned: Signature expired. In order to get a URL that can work properly, you need to replace the SecretId and SecretKey in the example with your real credentials and use the current time of the system as the Timestamp.

Note: In the example below, the URLs generated may be different in the order of the parameters during each execution with different or even the same programming languages, but this does not affect the correctness. As long as all parameters are in place and the signature is calculated correctly, it would be okay.

Note: The following code is only applicable to API 3.0. It cannot be directly used in other signature processes. Even with an older API, signature calculation errors may occur due to the difference in details. Please refer to the corresponding documentation.

Java

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Random;
import java.util.TreeMap;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;

public class TencentCloudAPIDemo {
    private final static String CHARSET = "UTF-8";

    public static String sign(String s, String key, String method) throws Exception {
        Mac mac = Mac.getInstance(method);
        SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(CHARSET), mac.getAlgorithm());
        mac.init(secretKeySpec);
        byte[] hash = mac.doFinal(s.getBytes(CHARSET));
        return DatatypeConverter.printBase64Binary(hash);
    }

    public static String getStringToSign(TreeMap<String, Object> params) {
        StringBuilder s2s = new StringBuilder("GETcvm.tencentcloudapi.com/?");
        // When signing, the parameters need to be sorted in lexicographical order. TreeMap is used here to guarantee the correct order
        for (String k : params.keySet()) {
            s2s.append(k).append("=").append(params.get(k).toString()).append("&");
        }
        return s2s.toString().substring(0, s2s.length() - 1);
    }

    public static String getUrl(TreeMap<String, Object> params) throws UnsupportedEncodingException {
        StringBuilder url = new StringBuilder("https://cvm.tencentcloudapi.com/?");
        // There is no requirement for the order of the parameters in the actual request URL
        for (String k : params.keySet()) {
            // The request string needs to be URL encoded. As the Key is all in English letters, only the value is URL encoded here
            url.append(k).append("=").append(URLEncoder.encode(params.get(k).toString(), CHARSET)).append("&");
        }
        return url.toString().substring(0, url.length() - 1);
    }

    public static void main(String[] args) throws Exception {
        TreeMap<String, Object> params = new TreeMap<String, Object>(); // TreeMap can enable auto sorting
        // A random numbers should be used when actually calling, for example: params.put("Nonce", new Random().nextInt(java.lang.Integer.MAX_VALUE));
        params.put("Nonce", 11886); // Common parameter
        // The current time of the system should be used when actually calling, for example: params.put("Timestamp", System.currentTimeMillis() / 1000);
        params.put("Timestamp", 1465185768); // Common parameter
        params.put("SecretId", "AKIDz8krbsJ5yKBZQpn74WFkmLPx3EXAMPLE"); // Common parameter
        params.put("Action", "DescribeInstances"); // Common parameter
        params.put("Version", "2017-03-12"); // Common parameter
        params.put("Region", "ap-guangzhou"); // Common parameter
        params.put("Limit", 20); // Business parameter
        params.put("Offset", 0); // Business parameter
        params.put("InstanceIds.0", "ins-09dx96dg"); // Business parameter
        params.put("Signature", sign(getStringToSign(params), "Gu5t9xGARNpq86cd98joQYCN3EXAMPLE", "HmacSHA1")); // Common parameter
        System.out.println(getUrl(params));
    }
}

Python

Note: If running in a Python 2 environment, the following requests dependency package must be installed first: pip install requests.

# -*- coding: utf8 -*-
import base64
import hashlib
import hmac
import time

import requests

secret_id = "AKIDz8krbsJ5yKBZQpn74WFkmLPx3EXAMPLE"
secret_key = "Gu5t9xGARNpq86cd98joQYCN3EXAMPLE"

def get_string_to_sign(method, endpoint, params):
    s = method + endpoint + "/?"
    query_str = "&".join("%s=%s" % (k, params[k]) for k in sorted(params))
    return s + query_str

def sign_str(key, s, method):
    hmac_str = hmac.new(key.encode("utf8"), s.encode("utf8"), method).digest()
    return base64.b64encode(hmac_str)

if __name__ == '__main__':
    endpoint = "cvm.tencentcloudapi.com"
    data = {
        'Action' : 'DescribeInstances',
        'InstanceIds.0' : 'ins-09dx96dg',
        'Limit' : 20,
        'Nonce' : 11886,
        'Offset' : 0,
        'Region' : 'ap-guangzhou',
        'SecretId' : secret_id,
        'Timestamp' : 1465185768, # int(time.time())
        'Version': '2017-03-12'
    }
    s = get_string_to_sign("GET", endpoint, data)
    data["Signature"] = sign_str(secret_key, s, hashlib.sha1)
    print(data["Signature"])
    # An actual calling would occur here which may incur fees after success
    # resp = requests.get("https://" + endpoint, params=data)
    # print(resp.url)