Alipay, China's leading third-party online payment solutionAlipay, China's leading third-party online payment solution

Sign a request and verify the signature

To ensure the authenticity and integrity of data after transmission, Alipay requires all requests to be signed and the signatures to be verified:

  • When calling an API, you must sign the request sent to Alipay and verify the Alipay response signature accordingly. For more information, see Call an API.
  • When receiving a notification, you must verify the Alipay request signature. However, you do not need to sign the response for the notification. For more information, see Receive a notification.

Call an API

Prerequisite

To sign a request, generate a pair of asymmetric public and private keys using the RSA2 method. You can download the tool on Antom Dashboard to get a pair of asymmetric keys.

The private key is used to generate the signature of a request, and you submit the asymmetric public key in the Set public key section under Integration Settings. Alipay uses the public key to verify your request signature.

Sign a request

The following figure shows how to sign a request:

image.png

Figure 2. How to sign a request

Step 1: Construct the content to be signed

The syntax of Content_To_Be_Signed is as follows:

copy
<HTTP-Method> <HTTP-URI>
<Client-Id>.<Request-Time>.<Request-Body>
  • HTTP-Method: POST
  • HTTP-URI: For example, if the HTTP URL is https://open-na-global.alipay.com/ams/api/v1/payments/pay, this field is /ams/api/v1/payments/pay.
  • Client-Id: Used to identify a client. For example, TEST_5X00000000000000. You can get this field from the request header.
  • Request-Time: Specifies the timestamp of when a request is sent. The value of this field must be accurate to milliseconds. For example, 1685599933871. You can get the timestamp from the request header.
  • Request-Body: The data body of the request. For example:
copy
{
 "order":{
    "orderId":"OrderID_0101010101",
    "orderDescription":"sample_order",
    "orderAmount":{
       "value":"100",
       "currency":"JPY"}
 }
}

By complying with the syntax of Content_To_Be_Signed, the request body above is constructed as follows:

copy
POST /ams/api/v1/payments/pay
TEST_5X00000000000000.2019-05-28T12:12:12+08:00.{
"order":{
    "orderId":"OrderID_0101010101",
    "orderDescription":"sample_order",
    "orderAmount":{
       "value":"100",
       "currency":"JPY"}
 } 
}

Step 2: Generate the signature

The syntax of generating the signature is as follows:

copy
generatedSignature=base64UrlEncode(sha256withrsa(<Content_To_Be_Signed>), <privateKey>))
  • sha256withrsa: The method to generate a digital signature for the provided content
  • base64UrlEncode: The method to encode the generated digital signature
  • Content_To_Be_Signed: The content obtained from Step 1
  • privateKey: The private key value obtained from Prerequisite

An example of a generated signature is as follows:

copy
KrwDE9tAPJYBb4cUZU6ALJxGIZgwDXn5UkFPMip09n%2FkYKPhEIII%2Fki2rYY2lPtuKVgMNz%2BtuCU%
2FjzRpohDbrOd8zYriiukpGAxBQDIVbatGI7WYOcc9YVQwdCR6ROuRQvr%2FD1AfdhHd6waAASu5Xugow9
w1OW7Ti93LTd0tcyEWQYd2S7c3A73sHOJNYl8DC1PjasiBozZ%2FADgb7ONsqHo%2B8fKHsLygX9cuMkQY
TGIRBQsvfgICnJhh%2BzXV8AQoecJBTrv6p%xxxx

The following code sample shows how to use java to sign a request:

copy
/**
     * 
     * @param requestURI // domain part excluded, sample: /ams/api/v1/payments/pay
     * @param clientId
     * @param requestTime
     * @param privateKey
     * @param requestBody
     * @return
     */
    public static String sign(String requestURI, String clientId, String requestTime,
                              String privateKey, String requestBody) {

        String content = String.format("POST %s\n%s.%s.%s", requestURI, clientId, requestTime,
            requestBody);

        try {
            java.security.Signature signature = java.security.Signature
                .getInstance("SHA256withRSA");

            PrivateKey priKey = KeyFactory.getInstance("RSA").generatePrivate(
                new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKey.getBytes("UTF-8"))));

            signature.initSign(priKey);
            signature.update(content.getBytes("UTF-8"));

            byte[] signed = signature.sign();

            return URLEncoder.encode(new String(Base64.encodeBase64(signed), "UTF-8"), "UTF-8");
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

Step 3: Add the generated signature to the request header

  1. Assemble a signature string based on the following syntax:
copy
'Signature: algorithm=<algorithm>, keyVersion=<key-version>, signature=<generatedSignature>'
  • algorithm, keyVersion: See the header of the Message structure chapter.
  • generatedSignature: The signature generated in Step 2.

For example:

copy
'Signature: algorithm=RSA256, keyVersion=1, signature=KrwDE9tAPJYBb4cUZU6ALJxGIZgwDXn5UkFPMip09n%2FkYKPhEIII%2Fki2rYY2lPtuKVgMNz%2BtuCU%2FjzRpohDbrOd8zYriiukpGAxBQDIVbatGI7WYOcc9YVQwdCR6ROuRQvr%2FD1AfdhHd6waAASu5Xugow9w1OW7Ti93LTd0tcyEWQYd2S7c3A73sHOJNYl8DC1PjasiBozZ%2FADgb7ONsqHo%2B8fKHsLygX9cuMkQYTGIRBQsvfgICnJhh%2BzXV8AQoecJBTrv6p%****'
  1. Add the signature string to the request header. For details about the request header, see the Message structure chapter.

Send a request

Construct a request by adding the Client-Id, Request-Time, and Signature properties to the request header. After a request is constructed, you can use common tools, such as cURL or Postman to send the request. In the following example, cURL is used:

copy
curl -X POST \
  https://www.example.com/ams/api/v1/payments/pay \
  -H 'Content-Type: application/json' \
  -H 'Client-Id: TEST_5X00000000000000' \
  -H 'Request-Time: 1685599933871' \
  -H 'Signature: algorithm=RSA256, keyVersion=0, signature=KrwDE9tAPJYBb4cUZU6ALJxGIZgwDXn5UkFPMip09n%2FkYKPhEIII%2Fki2rYY2lPtuKVgMNz%2BtuCU%2FjzRpohDbrOd8zYriiukpGAxBQDIVbatGI7WYOcc9YVQwdCR6ROuRQvr%2FD1AfdhHd6waAASu5Xugow9w1OW7Ti93LTd0tcyEWQYd2S7c3A73sHOJNYl8DC1PjasiBozZ%2FADgb7ONsqHo%2B8fKHsLygX9cuMkQYTGIRBQsvfgICnJhh%2BzXV8AQoecJBTrv6p%xxxx' \
  -d '{
      "order":{
          "orderId":"OrderID_0101010101",
          "orderDescription":"sample_order",
          "orderAmount":{
             "value":"100",
             "currency":"JPY"
          }
       },
       "paymentAmount":{
          "value":"100",
          "currency":"JPY"
       },
       "paymentFactor": {
           "isInStorePayment": "true"
       } 
}'

Handle a response

After receiving a response from Alipay, verify the signature of the response. The following figure shows how to verify a signature:

image.png

Figure 3. How to verify a signature

A response consists of the response header and the response body. For example:

  • Code sample of the response header:
copy
Client-Id: 5X00000000000000
Response-Time: 2019-05-28T12:12:14+08:00
signature: algorithm=RSA256, keyVersion=0, signature=p9T2hXxIjek0UOLw3fwlthNsV6ATaioIvu8X1uFx8a9tE87d2XEhqylnf0KjifJ3WhCoMokl
GwwlDS3tsSenwnL0Ha6BsXbJvUHRC5qcVlNy5Oq%2FpNqx2%2BKdwbw4eY7tZBDQhMKoaMVSbqbCb3eRBX
sw9ZwOO%2FFCyq1zICzllOd4pbhpvES3gcw2X%2B0Ye4hQJBghcLCJxCizSv9lMyTmV%2BYA39B9gRouha
N0dM2aeAXMlVJAWtJdcL%2Bdub%2F3LrzxBnY%****
  • Code sample of the response body:
copy
{
"result": {
    "resultCode":"SUCCESS",
    "resultStatus":"S",
    "resultMessage":"success"
    }
}

The following steps demonstrate how to handle a response from Alipay by using the examples above.

Step 1: Obtain Alipay public key

Obtain the Alipay public key through Antom Dashboard > Developer > Quick start > Integration resources and tools > Integration resources.

Note: Only when you upload your asymmetric public key to Antom Dashboard, can you obtain the Alipay public key used to verify the corresponding response from Alipay.

Step 2: Construct the content to be verified

The syntax of Content_To_Be_Validate is as follows:

copy
<HTTP-Method> <HTTP-URI>
<Client-Id>.<Response-Time>.<Response-Body>
  • HTTP-Method: POST
  • HTTP-URI: For example, if the HTTP URL is https://open-na-global.alipay.com/ams/api/v1/payments/pay, this field is /ams/api/v1/payments/pay.
  • Client-Id: Used to identify a client. You can get this field from the response header.
  • Response-Time: Specifies the time when a response is returned, as defined by ISO 8601. This field must be accurate to milliseconds. For example, 2019-05-28T12:12:14+08:00. You can get this field from the response header.
  • Response-Body: The data body of the response.

By complying with the syntax of Content_To_Be_Validated, construct the response given above as follows:

copy
POST /ams/api/v1/payments/pay
TEST_5X00000000000000.2019-05-28T12:12:14+08:00.{
 "result": {
    "resultCode":"SUCCESS",
    "resultStatus":"S",
    "resultMessage":"success"
   }
}

Step 3: Get the signature from the response header

The target signature string (target_signature) can be extracted from the Signature header in the response header. For details about the response header, see Message structure.

Code sample of Signature:

Signature: algorithm=RSA256, signature=<target_signature>

Step 4: Verify the signature

The syntax of validating the signature is as follows:

copy
IS_SIGNATURE_VALID=sha256withrsa_verify(base64UrlDecode(<target_signature>), <Content_To_Be_Validated>, <serverPublicKey>)
  • sha256withrsa_verify: The method to verify the signature
  • base64UrlDecode: The method to decode the signature
  • target_signature: The target signature obtained from step 3
  • content_to_be_verified: The content to be verified, created from step 2
  • serverPublicKey: The Alipay public key obtained from step 1
  • IS_SIGNATURE_VALID: A Boolean value that specifies whether the signature is valid
    • true: The signature is valid.
    • false: The signature is not valid. The cause can be a mismatch between the private key and public key, or Content_To_Be_Validated is not correctly constructed.

The following sample code shows how to use Java to verify the signature:

copy
/**
     * 
     * @param requestURI // domain part excluded, sample: /ams/api/v1/payments/pay
     * @param clientId
     * @param reponseTime
     * @param alipayPublicKey
     * @param responseBody
     * @param signatureToBeVerified
     * @return
     */
    public static boolean verify(String requestURI, String clientId, String reponseTime,
                                 String alipayPublicKey, String responseBody,
                                 String signatureToBeVerified) {

        //signatureToBeVerified would not be present in the response when AMS returns a SIGNATURE_INVALID
        if (StringUtil.isBlank(signatureToBeVerified)) {
            return false;
        }

        String content = String.format("POST %s\n%s.%s.%s", requestURI, clientId, reponseTime,
            responseBody);

        try {
            java.security.Signature signature = java.security.Signature
                .getInstance("SHA256withRSA");

            PublicKey pubKey = KeyFactory.getInstance("RSA").generatePublic(
                new X509EncodedKeySpec(Base64.decodeBase64(alipayPublicKey.getBytes("UTF-8"))));

            signature.initVerify(pubKey);
            signature.update(content.getBytes("UTF-8"));

            return signature.verify(Base64.decodeBase64(URLDecoder.decode(signatureToBeVerified,
                "UTF-8").getBytes("UTF-8")));

        } catch (Exception e) {
            throw new RuntimeException(e);
        }

    }

Receive a notification

Handle a request

After receiving a notification from Alipay, verify the signature of the request. The process of verifying the request signature is similar to the process introduced in the Handle a response section. To verify the signature, follow these steps:

  1. Obtain the Alipay public key for the request to verify the signature.
  2. Construct the request to be verified by complying with the syntax of Content_To_Be_Validated:
copy
<HTTP-METHOD> <Request-URI> 
<Client-Id>.<Request-Time>.<Request-Body>
  1. Get the signature from the request header.
  2. Verify the signature.