Welcome to Zuora Product Documentation

Explore our rich library of product information

Validate the Advanced Digital Signature

Learn how to validate the Advanced digital signature for Payment Pages 2.0, ensuring secure transmission of sensitive data.

For added security, you can use the Advanced digital signature for Payment Pages 2.0. For the Advanced signature, Zuora creates the signature with Tenant ID, Page ID, Token, Timestamp, as well as all pass-through URL parameters, encrypted Payment Method ID, and Error Code. Upon receiving the signature, the client verifies the signature using the public key, and comparing the values with the parameter values on the URL. Furthermore, the client will decrypt the Payment Method ID as well.

This approach will ensure the following:

  • The Payment Method ID will not be passed over HTTPS in plain text

  • Since pass-through parameters, Payment Method ID and Error Code are signed with the signature, once the signature is verified, the client can trust the values on the URL to be originated from Zuora.

The advanced signature will be generated using algorithm SHA512withRSA over a string that is concatenated with the following parts, delimited by the “#” character.

  • CallBack Path

  • Tenant ID

  • Host Page ID

  • Token (32 chars)

  • Timestamp (The time when we generate the signature)

  • Error Code

  • Passthrough parameters (field_passthrough[1,2,3,4,5]) Note: Though up to 15 passthrough parameters can be supported when passing in your client parameters, only the first 5 parameters are used for signature generation and validation.

  • Payment Method ID signed with Private Key

To validate the Advanced digital signature response for a Payment Page :

  1. Include the Zuora Security library 1.1 ( zuora-rsa-security-1.1.jar ).
    • com.zuora.rsa.security.decrypt.SignatureDecrypter

    • com.zuora.rsa.security.decrypt.FieldDecrypter

  2. Parse the callback parameters returned from Zuora and get the signature.
  3. Decrypt the Payment Page ID and the Payment Method using the public key. See Obtain the Public Key for Payment Pages 2.0 for getting the public key.
  4. Construct a string with the following values returned in the callback URL:
    • Callback URL

    • Tenant ID

    • Token

    • Timestamp

    • Decrypted pageId

    • Error code

    • Passthrough parameters (field_passthrough[1,2,3,4,5]) Note: Though up to 15 passthrough parameters can be supported when passing in your client parameters, only the first 5 parameters are used for signature generation and validation.

    • Decrypted payment method id

  5. Use the SignatureDecrypter.verifyAdvancedSignature method to validate the signature and compare the signature against the parameter values on the URL.
  6. Check if the signature timestamp is expired, i.e. the difference between the current time and the signature timestamp is more than 5 minutes.

The following code shows a sample implementation of the verification steps. This sample code to validate the advanced signature can be found in the latest version of the Payment Pages 2.0 sample code suite on Zuora GitHub site.

//Step 1: Include the Zuora Security library 1.1 (zuora-rsa-security-1.1.jar)
com.zuora.rsa.security.decrypt.SignatureDecrypter;
com.zuora.rsa.security.decrypt.FieldDecrypter;
//Step 2: Get the signature from the callback parameter.
String signature = new String(request.getParameter("signature").getBytes("iso-8859-1"), "UTF-8"); //Make sure using correct character encoding standard.
//Step 3: Construct the string to be encrypted.
String DELIM="#";
String timestamp = request.getParameter("timestamp");
String pageId = FieldDecrypter.decrypt(request.getParameter("pageId"), publicKeyString );
String paymentMethodId = FieldDecrypter.decrypt(request.getParameter("refId"), publicKeyString);
StringBuilder encryptedString = new StringBuilder();
encryptedString.append( "/hpm2samplecodejsp/webcontent/callback.jsp"); //Use your callback url instead in your page configration
encryptedString.append( DELIM + request.getParameter("tenantId") );
encryptedString.append( DELIM + request.getParameter("token"));
encryptedString.append( DELIM + timestamp);
encryptedString.append( DELIM + pageId);
encryptedString.append( DELIM + (request.getParameter("errorCode") == null?"":request.getParameter("errorCode") ));
encryptedString.append( DELIM + (request.getParameter("field_passthrough1") == null? "":request.getParameter("field_passthrough1")));
encryptedString.append( DELIM + (request.getParameter("field_passthrough2") == null? "":request.getParameter("field_passthrough2")));
encryptedString.append( DELIM + (request.getParameter("field_passthrough3") == null? "":request.getParameter("field_passthrough3")));
encryptedString.append( DELIM + (request.getParameter("field_passthrough4") == null? "":request.getParameter("field_passthrough4")));
encryptedString.append( DELIM + (request.getParameter("field_passthrough5") == null? "":request.getParameter("field_passthrough5")));
encryptedString.append( DELIM + paymentMethodId );
//Step 4: Verify the signature. (Need zuora-rsa-security-1.1.jar )
boolean isSignatureValid = false;
isSignatureValid = SignatureDecrypter.verifyAdvancedSignature(signature, encryptedString.toString(), publicKeyString);
if( !isSignatureValid ){
    // signature is invalid.
    throw new Exception("Signature is invalid."); 
}
//Step 5: Validate that the signature is not expired.
long expiredTime = 5 * 60 * 1000;
if((new Date()).getTime() > (Long.parseLong(timestamp) + expiredTime)) {
    // signature is expired.
    throw new Exception("Signature is expired.");
}