Sign Requests for App Authorization

Last Updated on : 2024-07-02 06:13:02download

When you make requests to APIs, you must provide a signature to verify your identity and ensure data security. This topic describes how to generate a signature in a request.

Signature algorithm

HMAC-SHA256 is used in API services to create a message digest. Different signature algorithms are applied to token management API requests and general API requests, as described in the following table.

API type Token management API General business API
Scope of application Requests that are made to get or refresh tokens Requests that are made to manage business rather than tokens.
Signature algorithm str = client_id + t + nonce + identifier + stringToSign
sign = HMAC-SHA256(str, secret).toUpperCase()
str = client_id + access_token + t + nonce + identifier + stringToSign
sign = HMAC-SHA256(str, secret).toUpperCase()
Field description
  • client_id: the key of an authentication key pair.
  • t: the 13-digit standard timestamp.
  • nonce: the universally unique identifier (UUID) generated for each API request. Combined with the timestamp, the UUID ensures the uniqueness of API requests. This field is optional.
  • identifier: The custom signature content for app authorization. When the authorization type is Android, you need to concatenate SHA1 and Application ID to form an identifier without a separator. For other types, you can directly use the customized Bundle Identifier.
  • stringToSign: the signature string. For more information, see stringToSign.
  • secret: the value of an authentication key pair.
  • access_token: the access token. The field value is obtained from the authentication key pair.
Field description Concatenate the value of client_id, the 13-digit standard timestamp (t) of the specified request, nonce, identifier, and stringToSign to create a string named as str. Use HMAC-SHA256 to create a hash digest value based on the string str and the value of the secret. Capitalize all letters of the hash digest value to get a signature.

Different from token management API requests, in the signature algorithm for general API requests, access_token is additionally concatenated to generate the string str.

stringToSign signature string

Structure

stringToSign is created in the following structure:

String stringToSign=
HTTPMethod + "\n" +
Content-SHA256 + "\n" +
Optional_Signature_key + "\n" +
URL

This structure consists of the following four parts:

  • HTTPMethod
  • Content-SHA256
  • Optional_Signature_key
  • URL

You can concatenate the strings of these four parts with line-feed characters (\n) to create a string-to-sign named as stringToSign.

HTTPMethod

HTTPMethod represents an API method, such as GET, POST, PUT, and DELETE.

Content-SHA256

Content-SHA256 represents the SHA256 value of a request body. SHA256 is calculated only when the body is not a form.

Calculation:

String content-SHA256 = SHA256(bodyStream.getbytes("UTF-8")); // bodyStream is a byte array.

An empty body is still encrypted into e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855.

Optional_Signature_key

Optional_Signature_key represents the string in which all request headers involved in the signature calculation are concatenated with line-feed characters (\n) as described in Request Structure. Each request header is a key-value pair. For example:

  1. The request parameters are as follows:

    client_id: 1KAD46OrT9HafiKd****
    sign: C5EFD19AD45E33A060C0BE47AEF65D975D54B2D70CBAA7A1ACA1A7D0E5C0****
    sign_method: HMAC-SHA256
    t: 1588925778000
    access_token: 3f4eda2bdec17232f67c0b188af3****
    nonce: 5138cc3a9033d69856923fd07b49****
    ...
    
  2. To improve data security, add two custom fields area_id and req_id to the signature calculation.

    area_id: 29a33e8796834b1****
    req_id: 8afdb70ab2ed11eb85290242ac13****
    
  3. The new request structure as follows:

    client_id: 1KAD46OrT9HafiKd****
    sign: C5EFD19AD45E33A060C0BE47AEF65D975D54B2D70CBAA7A1ACA1A7D0E5C0****
    sign_method: HMAC-SHA256
    t: 1588925778000
    access_token: 3f4eda2bdec17232f67c0b188af3****
    nonce: 5138cc3a9033d69856923fd07b49****
    ...
    
     // Two request headers are added
    Signature-Headers: area_id:req_id
    area_id: 29a33e8796834b1**** // Subject to your customization
    req_id: 8afdb70ab2ed11eb85290242ac13****  // Subject to your customization
    

    All request header fields involved are concatenated with colons (:). As shown in the preceding code block, area_id:req_id is generated as the value of Signature-Headers.

    Then, concatenate all key-value pairs included in Signature-Headers to generate the value of Optional_Signature_key in the following structure:

    String Optional_Signature_key =
    Signature-Headers-Key1 + ":" + Signature-Headers-Value1 + "\n" +
    Signature-Headers-Key2 + ":" + Signature-Headers-Value2 + "\n" +
    ...
    Signature-Headers-KeyN + ":" + Signature-Headers-ValueN + "\n"
    

    In this example, the following value of Optional_Signature_key is obtained:

    String Optional_Signature_key =
    area_id + ":" + 29a33e8796834b1**** + "\n" +
    req_id + ":" + 8afdb70ab2ed11eb85290242ac13**** + "\n"
    

URL

A URL represents the request path into which a request path and form parameters are concatenated.

  • Concatenate URLs: Sort form parameters by keys in alphabetically ascending order and concatenated in the following way. If query parameters or form parameters are empty, set the URL to the request path that is not suffixed with a question mark (?).

    String url =
    Path +
    "?" +
    Key1 + "=" + Value1 +
    "&" + Key2 + "=" + Value2 +
    "&" + Key3 +
    ...
    "&" + KeyN + "=" + ValueN
    

    For example:

    String url = /v1.0/iot-03/devices/87707085bcddc23a5fa3/logs?end_time=1657263936000&event_types=1&start_time=1657160836000
    
  • Sort parameters in alphabetically ascending order. If multiple parameters have the same initial letter, sort these parameters by their second letter alphabetically. This way, letters are sequentially compared among different parameters until the parameters can be sorted as expected.

    Take the following parameters as an example:

    • start_time=1657160836000
    • end_time=1657263936000
    • event_types=1

    They are sorted in the following alphabetical order:

    • end_time=1657263936000

    • event_types=1

    • start_time=1657160836000

      In these parameters, end_time and event_types have the same initial letter, and the second letter n of end_time comes earlier in the alphabet than the second letter v of event_types. Therefore, end_time is followed by event_types.
      The first letter of end_time and event_types comes earlier in the alphabet than the first letter of start_time. As a result, end_time and event_types are followed by start_time.

Token management API example

In the following example, make an API request to get a token. Set grant_type to 2 and leave the body parameter empty.

GET:/v1.0/token?grant_type=2

The request header structure is as follows:

Parameter Value
method GET
client_id 1KAD46OrT9HafiKdsXeg
secret 4OHBOnWOqaEC1mWXOpVL3yV50s0qGSRC
t 1588925778000
sign_method HMAC-SHA256
nonce 5138cc3a9033d69856923fd07b491173
Signature-Headers area_id:call_id
area_id (Customized and used in signature calculation) 29a33e8796834b1efa6
call_id (Customized and used in signature calculation) 8afdb70ab2ed11eb85290242ac130003

Concatenate a stringToSign

Generate the string-to-sign stringToSign in the following structure:

GET
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
area_id:29a33e8796834b1efa6
call_id:8afdb70ab2ed11eb85290242ac130003

/v1.0/token?grant_type=2

The structure is described as follows:

Sign Requests for App Authorization

Create a string that includes the string-to-sign

After stringToSign is generated, you can use it to create the string str:

1KAD46OrT9HafiKdsXeg15889257780005138cc3a9033d69856923fd07b491173GET
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
area_id:29a33e8796834b1efa6
call_id:8afdb70ab2ed11eb85290242ac130003

/v1.0/token?grant_type=2

The structure is described as follows:

Sign Requests for App Authorization

Use HMAC-SHA256 to create a message digest

Hash digest value:

HMAC-SHA256(1KAD46OrT9HafiKdsXeg15889257780005138cc3a9033d69856923fd07b491173GET
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
area_id:29a33e8796834b1efa6
call_id:8afdb70ab2ed11eb85290242ac130003

/v1.0/token?grant_type=2,4OHBOnWOqaEC1mWXOpVL3yV50s0qGSRC)
  • Create a hash digest value and encode the hash digest value into a new string:

    9e48a3e93b302eeecc803c7241985d0a34eb944f40fb573c7b5c2a82158af13e

  • Capitalize all letters of the new string:

    9E48A3E93B302EEECC803C7241985D0A34EB944F40FB573C7B5C2A82158AF13E

General business API example

In the following example, make an API request to get a list of users. Set schema to apps and leave the body parameter empty.

Parameter Value
URL /v2.0/apps/schema/users
method GET
client_id 1KAD46OrT9HafiKdsXeg
secret 4OHBOnWOqaEC1mWXOpVL3yV50s0qGSRC
t 1588925778000
access_token 3f4eda2bdec17232f67c0b188af3eec1
sign_method HMAC-SHA256
nonce 5138cc3a9033d69856923fd07b491173
Signature-Headers area_id:call_id
area_id (Customized and used in signature calculation) 29a33e8796834b1efa6
call_id (Customized and used in signature calculation) 8afdb70ab2ed11eb85290242ac130003
page_no 1
page_size 50

Concatenate a stringToSign

Generate the string-to-sign stringToSign in the following structure:

GET
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
area_id:29a33e8796834b1efa6
call_id:8afdb70ab2ed11eb85290242ac130003

/v2.0/apps/schema/users?page_no=1&page_size=50

The structure is described as follows:

Sign Requests for App Authorization

Create a string that includes the string-to-sign

After stringToSign is generated, you can use it to create the string str:

1KAD46OrT9HafiKdsXeg3f4eda2bdec17232f67c0b188af3eec115889257780005138cc3a9033d69856923fd07b491173GET
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
area_id:29a33e8796834b1efa6
call_id:8afdb70ab2ed11eb85290242ac130003

/v2.0/apps/schema/users?page_no=1&page_size=50

The structure is described as follows:

Sign Requests for App Authorization

Use HMAC-SHA256 to create a message digest

Hash digest value:

HMAC-SHA256(1KAD46OrT9HafiKdsXeg3f4eda2bdec17232f67c0b188af3eec115889257780005138cc3a9033d69856923fd07b491173GET
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
area_id:29a33e8796834b1efa6
call_id:8afdb70ab2ed11eb85290242ac130003

/v2.0/apps/schema/users?page_no=1&page_size=50,4OHBOnWOqaEC1mWXOpVL3yV50s0qGSRC)
  • Create a hash digest value and encode the hash digest value into a new string:

    ae4481c692aa80b25f3a7e12c3a5fd9bbf6251539dd78e565a1a72a508a88784

  • Capitalize all letters of the new string:

    AE4481C692AA80B25F3A7E12C3A5FD9BBF6251539DD78E565A1A72A508A88784

Implement the HMAC-SHA256 authentication scheme

Sample code for Java

Download the sample code for Java.

Example for Golang

Download the sample code for Golang.

Sample code for Node.js

Download the sample code for Node.js.

Sample code for JavaScript

/**
Run the code online with this jsfiddle. Dependent upon an open source js library calledhttp://code.google.com/p/crypto-js/.
**/

<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/enc-base64.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/hmac-sha256.min.js"></script>

<script>
  var hash = CryptoJS.HmacSHA256("str", "secret");
  var hashInBase64 = hash.toString().toUpperCase();
  document.write(hashInBase64);
</script>

Sample code for PHP

/**
PHP has built-in methods for hash_hmac (PHP 5) and base64_encode (PHP 4, PHP 5) resulting in no outside dependencies. Say what you want about PHP but they have the cleanest code for this example.
**/

$s = strtoupper(hash_hmac("sha256", "str", 'secret'));
echo var_dump($s);

Sample code for C#

using System;
using System.Security.Cryptography;

namespace Test
{
  public class MyHmac
  {
    public static string Encrypt(string str, string secret)
            {
                secret = secret ?? "";
                var encoding = new System.Text.UTF8Encoding();
                byte[] keyByte = encoding.GetBytes(secret);
                byte[] messageBytes = encoding.GetBytes(str);
                using (var hmacsha256 = new HMACSHA256(keyByte))
                {
                    byte[] hashmessage = hmacsha256.ComputeHash(messageBytes);
                    StringBuilder builder = new StringBuilder();
                    for (int i = 0; i < hashmessage.Length; i++)
                    {
                        builder.Append(hashmessage[i].ToString("x2"));
                    }
                    return builder.ToString().ToUpper();
                }
            }
  }
}

FAQs

How do I verify the encrypted signature?

During local development, you can test API requests with Postman to verify the encrypted signature. For more information, see Verify Signature Result.

Why does a blank line exist in stringToSign?

This depends on the structure of stringToSign. stringToSign consists of HTTPMethod, Content-SHA256, Headers, and URL, concatenated with a line-feed character (\n) in between. The structure is as follows:

String stringToSign=
HTTPMethod + "\n" +
Content-SHA256 + "\n" +
Headers + "\n" +
URL

The following example shows how to calculate Headers:

String Headers =
HeaderKey1 + ":" + HeaderValue1 + "\n" +
HeaderKey2 + ":" + HeaderValue2 + "\n" +
...
HeaderKeyN + ":" + HeaderValueN + "\n"

Therefore, the Headers string is followed by two line-feed characters (\n) that result in a blank line.