Skip to main content

Description of External Interface Signature Authentication Algorithm

Description of External Interface Signature Authentication Algorithm#

Construct canonical request string and hash#

To use AK and SK for signature and authentication, you first need to standardize the content of the request and sign the content to call the open apis.

The pseudo code of the HTTP request specification is as follows:

CanonicalRequest =

HTTPRequestMethod + '\n' +

CanonicalURI + '\n' +

CanonicalQueryString + '\n' +

HexEncode(Hash(RequestPayload))

1. Construct HTTP request method (HTTPRequestMethod)#

HTTP request method, ending with a newline, such as GET, PUT, POST, etc. Example of request method:

GET
POST

2. Construct the URI parameter (CanonicalURI)#

Definition: Canonical URI, that is, the request resource path, is the absolute path part of the URI

Format: URI paths are standard according to RFC 3986, redundant and relative path parts are removed, each part of the path must be URI encoded. If the URI path does not end with "/", append "/" to the end

GET

/mp-api/v1/apps/ozSQnakAm7apa6ew7crPYd/user-open-data/

If the absolute path is empty, use a forward slash (/)

GET

/

POST

/mp-api/v1/apps/ozSQnakAm7apa6ew7crPYd/message/send/

3. Construct CanonicalQueryString#

Definition: query string, or empty string if there are no query parameters, that is, the request after specification is an empty line

Format: The canonical query string needs to meet the following requirements:

Each parameter name and value is URI encoded according to the following rules:

Do not URI encode any non-reserved characters defined by RFC 3986, these include: A-Z, a-z, 0-9, -, _, ., and ~.

All other characters are percent encoded using %XY, where X and Y are hexadecimal characters (0-9 and A-F). For example, space characters must be encoded as %20, and extended UTF-8 characters must be in the format "%XY%ZA%BC".

For each parameter, append "URI-encoded parameter name=URI-encoded parameter value". If there is no parameter value, an empty string is used instead, but "=" cannot be omitted.

For example, the following contains two parameters, where the value of the second parameter parm2 is empty.

parm1=value1&parm2=

Sort parameter names in ascending order by character code. For example, parameter names that begin with an uppercase F are sorted before parameter names that begin with a lowercase b.

Constructs the canonical query string, starting with the first sorted parameter name.

GET

/mp-api/v1/apps/ozSQnakAm7apa6ew7crPYd/user-open-data/

openData=dGVzdGNvZGU

POST

/mp-api/v1/apps/ozSQnakAm7apa6ew7crPYd/message/send/

4. The body in the body (RequestPayload)#

Definition: Request message body. The message body needs to do two layers of conversion: HexEncode(Hash(RequestPayload)), where Hash represents the function that generates the message digest, and currently supports the SHA-256 algorithm. HexEncode represents a function that returns the Base-16 encoding of the digest in lowercase letters. For example, HexEncode("m") returns "6d" instead of "6D". Each byte of input is represented as two hexadecimal characters.

When calculating the hash value of RequestPayload, for the scenario of "RequestPayload==null", use the empty string "" directly to calculate.

Example: This example is a GET method, and the body is empty. The hashed body (empty string) is as follows:

GET

/mp-api/v1/apps/ozSQnakAm7apa6ew7crPYd/user-open-data/

openData=dGVzdGNvZGU

e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855

POST

/mp-api/v1/apps/ozSQnakAm7apa6ew7crPYd/message/send/

5. Hash the constructed canonical request string#

Lowercase(HexEncode(Hash.SHA256(CanonicalRequest)))

Example: hashing the canonical request string

GET

/mp-api/v1/apps/ozSQnakAm7apa6ew7crPYd/user-open-data/

openData=dGVzdGNvZGU

e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855

# After encoding

e1b70e3bf69bd4be11ce20e94dc9f367e70bde420dc29ab591a6e06b8c3e872e

// {"appId":"ozSQnakAm7apa6ew7crPYd","language":"en","parameters":[{"name":"result","value":"success"},{"name":"withdrawMoney","value":"100"}],"path":"pages/details/index?source=push","pushToken":"push_token_ozSQnakAm7apa6ew7crPYd_template1_ABVREdsgregsdfhy","template_id":"template1"}

POST

/mp-api/v1/apps/ozSQnakAm7apa6ew7crPYd/message/send/

Beac504b39b372cedaf81e272aadec27b590b00ccea0dc1607a290f6ba7722af

# After encoding

647643a5642dceee80cafbfc89e6ead7ce59e70a80b598b814514b2fd9b1d432

6. Set the encoded string to the dig field of the JWT payload#

// GET

"payload":{

"iss":"APKADD5WRLZTBVTVCRJQ",

"dig":"e1b70e3bf69bd4be11ce20e94dc9f367e70bde420dc29ab591a6e06b8c3e872e"

}

//POST

"payload":{

"iss":"APKADD5WRLZTBVTVCRJQ",

"dig":"647643a5642dceee80cafbfc89e6ead7ce59e70a80b598b814514b2fd9b1d432"

}

Time in signature#

ts: timestamp, in seconds

"payload":{

"iss":"APKADD5WRLZTBVTVCRJQ",

"dig":"e1b70e3bf69bd4be11ce20e94dc9f367e70bde420dc29ab591a6e06b8c3e872e",

"ts":1647007152

}

Generate JWT and sign#

1. JWT payload struct#

NameDescriptionTypeRequired
issThe token issuer is AK of the access server or client.stringYes
digThe hashed HTTP canonical request string used to verify that the content has not been tampered withstringYes
ts

Signature time verification, which is a second-level GMT Unix Timestamp (the server will compare

this time with the server time, plus or minus cannot exceed 1 minute)

numberYes

2. Use SK to sign Token#

The signature is used to verify that the message has not been altered in transit, and, for tokens signed with a private key (SK), it also verifies that the sender of the JWT is what it claims to be.

AK: APKADD5WRLZTBVTVCRJQ

SecretKey: KFFICLR4U72D0S4AB3W4LXECWVWEIE0DA2AAYKER514ZLV1U

"header":{

"alg":"HS256",

"typ":"JWT"

},

"payload":{

"iss":"APKADD5WRLZTBVTVCRJQ",

"dig":"e1b70e3bf69bd4be11ce20e94dc9f367e70bde420dc29ab591a6e06b8c3e872e",

"ts":1647007152

},

"signature":"HMACSHA256(

base64UrlEncode(header) + "." +

base64UrlEncode(payload), "KFFICLR4U72D0S4AB3W4LXECWVWEIE0DA2AAYKER514ZLV1U")"

3. Demo sample code#

Javascript#
import axios from 'axios';import crypto from 'crypto'import jwt from 'jsonwebtoken';

const config = {    ak:'xxx',    sk:'xx',    appId: 'xx',    template_id: 'xx'}
const payload = {    appId: config.appId,    pushToken: 'xx',    templateId: config.template_id,    language: 'en',    path: 'pages/index/index',    parameters: [        {            name: "result",            data: 'test2'        },        {            name: "withdrawMoney",            data: 'test3'        }    ]}


function requestWrapper({ apiHost, ak, sk }) {    return async function request(url, method, data) {      const param = ''      const hash = crypto.createHash('sha256')            hash.update(JSON.stringify(data) || '')      const bodyHash = hash.digest('hex')            console.log(`bodyHash`,bodyHash)
      const body = `${method.toUpperCase()}${url}${url.endsWith('/') ? '' : '/'}${param}${bodyHash}`
  console.log(body)        const newHash = crypto.createHash('sha256')      newHash.update(body)        const token = await new Promise((resolve, reject) => {        jwt.sign(          JSON.stringify({            iss: ak,            dig: newHash.digest('hex'),            ts: Math.floor(Date.now() / 1000),          }),          sk,          { header: { alg: 'HS256', typ: 'JWT' } },          function (err, token) {            if (err) {              reject(err)            } else {              resolve(token || '')            }          }        )      })      console.log(`token`, token)            return axios        .request({          url,          baseURL: apiHost,          method,          data: JSON.stringify(data),          headers: {            'X-Mp-Open-Api-Token': token,          },        })        .then((res) => res.data)    }  }


const res = await requestWrapper({apiHost:'https://dip-cb.binanceapi.com',ak: config.ak, sk:config.sk})(`/mp-api/v1/apps/${config.appId}/message/send`,'POST', payload)

console.log(res, res)

Carrying JWT token request interface#

When requesting the interface, you need to add the generated JWT token to the HTTP header, as shown below

X-Mp-Open-Api-Token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJBUEtBREQ1V1JMWlRCVlRWQ1JKUSIsImRpZyI6ImUxYjcwZTNiZjY5YmQ0YmUxMWNlMjBlOTRkYzlmMzY3ZTcwYmRlNDIwZGMyOWFiNTkxYTZlMDZiOGMzZTg3MmUiLCJ0cyI6MTY0NzAwNzE1Mn0.7OD8RGEyRHs4ieTZg52v6z263nV0eePXDe7WJQYkVn8

  • Description of External Interface Signature Authentication Algorithm
    • Construct canonical request string and hash
    • Time in signature
    • Generate JWT and sign
    • Carrying JWT token request interface