Sign a request and validate the signature
Before calling an API, you must sign all HTTPS API requests to ensure security, and then validate the response signature accordingly.
Sign a request
The following graphic shows an overview of the signature creation process:
Figure 1. Signature creation process
Procedure
- Obtain your private key (
privateKey
) that is used to sign the request. - Construct the content to be signed (
Content_To_Be_Signed
). - Calculate and generate the signature.
- Add the generated signature to the request header.
For details of each step, see the following examples.
Step 1: Obtain your private key to sign the request
Get your private key ready, it is used to generate the signature later.
Step 2: Construct the content to be signed
The syntax of Content_To_Be_Signed
is as below:
<HTTP-Method> <HTTP-URI>
<Client-Id>.<Request-Time>.<Request-Body>
HTTP-Method
: POSTHTTP-URI
: For example, if the HTTP URL is https://open-na.alipay.com/ams/api/v1/payments/refund, this field is/ams/api/v1/payments/refund
.Client-Id
: Used to identify a client. For example,SANDBOX_5Y0566SG25J004124
. You can get this field from the request header.Request-Time
: Specifies the time when a request is sent, as defined by ISO 8601. This field must be accurate to milliseconds. For example,2019-05-28T12:12:12+08:00
. You can get this field from the request header.Request-Body
: The data body of the request. For example:
{
"order":{
"orderId":"OrderID_0101010101",
"orderDescription":"sample_order",
"orderAmount":{
"value":"100",
"currency":"JPY"
},
},
"paymentAmount":{
"value":"100",
"currency":"JPY"
},
"paymentFactor": {
"isInStorePayment": "true"
}
}
By complying with the syntax of Content_To_Be_Signed
, the content to be signed (Content_To_Be_Signed
) is created as follows:
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"
},
},
"paymentAmount":{
"value":"100",
"currency":"JPY"
},
"paymentFactor": {
"isInStorePayment": "true"
}
}
Step 3: Calculate and generate the signature
Use the base64UrlEncode
and sha256withrsa
methods that involve the proper algorithm and private key to calculate and generate the signature.
generatedSignature=base64UrlEncode(sha256withrsa(<Content_To_Be_Signed>), <privateKey>))
Methods used:
sha256withrsa
: The method to generate a digital signature for the content provided.base64UrlEncode
: The method to encode the generated digital signature.
Input parameters:
Content_To_Be_Signed
: The content to be signed that is obtained in step 2.privateKey
: The private key value that is obtained in step 1.
For example, the generated signature generatedSignature
looks as follows:
KrwDE9tAPJYBb4cUZU6ALJxGIZgwDXn5UkFPMip09n%2FkYKPhEIII%2Fki2rYY2lPtuKVgMNz%2BtuCU%
2FjzRpohDbrOd8zYriiukpGAxBQDIVbatGI7WYOcc9YVQwdCR6ROuRQvr%2FD1AfdhHd6waAASu5Xugow9
w1OW7Ti93LTd0tcyEWQYd2S7c3A73sHOJNYl8DC1PjasiBozZ%2FADgb7ONsqHo%2B8fKHsLygX9cuMkQY
TGIRBQsvfgICnJhh%2BzXV8AQoecJBTrv6p%xxxx
The following demo code shows how to use java to sign the request:
/**
*
* @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 4: Add the generated signature to the request header
a. Assemble a signature string based on the following syntax:
'Signature: algorithm=<algorithm>, keyVersion=<key-version>, signature=<generatedSignature>'
algorithm
,keyVersion
: See the header of the Message structure chapter.generatedSignature
: The signature that is generated in step 3.
For example:
'Signature: algorithm=RSA256, keyVersion=1, signature=KrwDE9tAPJYBb4cUZU6ALJxGIZgwDXn5UkFPMip09n%2FkYKPhEIII%2Fki2rYY2lPtuKVgMNz%2BtuCU%2FjzRpohDbrOd8zYriiukpGAxBQDIVbatGI7WYOcc9YVQwdCR6ROuRQvr%2FD1AfdhHd6waAASu5Xugow9w1OW7Ti93LTd0tcyEWQYd2S7c3A73sHOJNYl8DC1PjasiBozZ%2FADgb7ONsqHo%2B8fKHsLygX9cuMkQYTGIRBQsvfgICnJhh%2BzXV8AQoecJBTrv6p%****'
b. 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, like cURL or Postman to send the request. In the following example, cURL is used.
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: 2019-05-28T12:12:12+08:00' \
-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 you receive a response, you need to validate the signature of the response. The following graphic shows an overview of the signature validation process:
Figure 2. Signature validation process
A response consists of the response header and the response body. For example:
- Code sample of the response header:
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:
{
"result": {
"resultCode":"SUCCESS",
"resultStatus":"S",
"resultMessage":"success"
},
"paymentTime": "2019-05-28T12:12:13+08:00",
"paymentId":"1234567"
}
Procedure
- Obtain the platform public key.
- Construct the content to be validated (
Content_To_Be_Validated
). - Get the signature from the response header.
- Validate the signature.
For details of each step, see the following examples.
Step 1: Obtain the platform public key
The Client-Id and algorithm properties can be obtained from the response header. You can create asymmetric keys by using the tool provided in Alipay Developer Center or by generating them yourself. You can set up and then exchange keys for the sandbox and production environments respectively with the provided tool. The key generation tool and the space to configure the key are as below:
Figure 3. Set public key
Step 2: Construct the content to be validated
By complying with the Syntax of Content_To_Be_Validated
, construct the content to be validated (Content_To_Be_Validated
) as follows:
POST /ams/api/v1/payments/pay
TEST_5X00000000000000.2019-05-28T12:12:14+08:00.{
"result": {
"resultCode":"SUCCESS",
"resultStatus":"S",
"resultMessage":"success"
},
"paymentTime": "2019-05-28T12:12:13+08:00",
"paymentId":"1234567"
}
Syntax of Content_To_Be_Validated
<HTTP-Method> <HTTP-URI>
<Client-Id>.<Response-Time>.<Response-Body>
Create the string to be validated. For example, a response has the following properties:
HTTP-Method
: POSTHTTP-URI
: For example, if the HTTP URL is https://open-na.alipay.com/ams/api/v1/payments/refund, this field is/ams/api/v1/payments/refund
.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.
Step 3: Get the signature from the response header
The target signature string (target_signature
) can be extracted from the Signature
header of the response. For details about the response header, see Message structure.
Code sample of signature:
Signature: algorithm=RSA256, signature=<target_signature>
Step 4: Validate the signature
Use the sha256withrsa_verify
method to validate the signature of the response.
The syntax of the sha256withrsa_verify
method is as follows:
IS_SIGNATURE_VALID=sha256withrsa_verify(base64UrlDecode(<target_signature>), <Content_To_Be_Validated>, <serverPublicKey>)
Methods used:
sha256withrsa_verify
: The method to verify the signature.base64UrlDecode
: The method to decode the signature.
Input parameters:
target_signature
: The target signature that is obtained from step 3.content_to_be_verified
: The content to be validated that is created from step 2.serverPublicKey
: The platform public key obtained from step 1.
Output parameters:
IS_SIGNATURE_VALID
: a Boolean value that specifies whether the signature is valid.
true
: The signature is valid.false
: The signature is inot valid. The cause can be a mismatch that between the private key and public key, orContent_To_Be_Validated
is not correctly constructed.
The following demo code shows how to use Java to validate the signature:
/**
*
* @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);
}
}