WeChat Channel Partner Scan-to-Dine Data Reporting Implementation

Authentication and Certificate Management

Secure communication requires proper certificate handling distinct from merchant platform API secrets. You must utilize WeChat-provided certificates including the p12 bundle and PEM files (cert.pem, key.pem). When configuring these files, strip unnecesasry headers and footers, retaining only the string content without newline characters. For decryption tasks involving encrypted payloads, the APIv3 secret key is mandatory. Ensure your account is whitelisted for APIv3 access before attempting decryption to avoid runtime errors.

Request Signature Generaiton

Digital signatures utilize the SHA256withRSA algorithm. The private key supplied to the signing process must be Base64-encoded PKCS8 format.

import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;

public class CryptoUtils {
    /**
     * Generates a digital signature for incoming request data.
     *
     * @param sourceData The raw payload requiring authentication
     * @param pemKey     The private key in PEM format (Base64 encoded)
     * @return Hexadecimal string representation of the signature
     */
    public static String generateSignature(String sourceData, String pemKey) {
        try {
            byte[] decodedKey = Base64.getDecoder().decode(pemKey.getBytes());
            PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(decodedKey);
            KeyFactory factory = KeyFactory.getInstance("RSA");
            PrivateKey privateKey = factory.generatePrivate(spec);

            Signature signer = Signature.getInstance("SHA256withRSA");
            signer.initSign(privateKey);
            signer.update(sourceData.getBytes("UTF-8"));

            byte[] signatureBytes = signer.sign();
            return Base64.getEncoder().encodeToString(signatureBytes);
        } catch (Exception ex) {
            // Handle logging appropriately
        }
        return null;
    }
}

Decryption Logic

Decrypting messages sent from WeChat requires the AEAD_AES_256_GCM cipher mode. The process involves the APIv3 key as the symmetric key material. Incorrect key configuration typically results in tag mismatch exceptions.

import javax.crypto.Cipher;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;

public class MessageProcessor {
    private static final String ALGORITHM = "AES/GCM/NoPadding";

    /**
     * Decrypts the associated ciphertext using AES-GCM.
     *
     * @param aad      Associated authenticated data (constant string)
     * @param nonce    Initialization vector
     * @param ciphertext Encoded ciphertext received from the gateway
     * @return Decrypted plaintext content
     */
    public static String decryptPayload(String aad, String nonce, String ciphertext) {
        try {
            Cipher cipher = Cipher.getInstance(ALGORITHM);
            SecretKeySpec keySpec = new SecretKeySpec(API_V3_KEY.getBytes(), "AES");
            GCMParameterSpec spec = new GCMParameterSpec(128, nonce.getBytes());

            cipher.init(Cipher.DECRYPT_MODE, keySpec, spec);
            cipher.updateAAD(aad.getBytes());

            byte[] decrypted = cipher.doFinal(Base64.getDecoder().decode(ciphertext));
            return new String(decrypted, "UTF-8");
        } catch (Exception e) {
            return null;
        }
    }
}

Response Verification

Verifying signatures from WeChat utilizes the public certificate file. Load the X509 certificate to extract the public key component for validation.

import java.io.FileInputStream;
import java.security.PublicKey;
import java.security.cert.X509Certificate;
import java.security.Signature;
import java.nio.file.Files;
import java.nio.charset.StandardCharsets;

public class Verifier {
    /**
     * Validates the authenticity of a signed message.
     *
     * @param payload          The data that was signed
     * @param signatureString  The Base64 encoded signature provided by the sender
     * @param certPath         File path to the WeChat public certificate
     * @return True if verification succeeds, false otherwise
     */
    public static boolean validate(String payload, String signatureString, String certPath) {
        try {
            byte[] certData = Files.readAllBytes(java.nio.file.Paths.get(certPath));
            X509Certificate certificate = X509Certificate.getInstance(certData);
            PublicKey publicKey = certificate.getPublicKey();

            Signature verifier = Signature.getInstance("SHA256withRSA");
            verifier.initVerify(publicKey);
            verifier.update(payload.getBytes(StandardCharsets.UTF_8));

            byte[] sigBytes = java.util.Base64.getDecoder().decode(signatureString);
            return verifier.verify(sigBytes);
        } catch (Exception ignored) {
            return false;
        }
    }
}

Constructing the HTTP Request

Proper header construction is critical for successful transmission. Even GET requests containing parameters may require a newline character in specific contexts to pass parsing checks. Always construct the Authorization header precisely according to the specification.

import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import java.nio.charset.StandardCharsets;

public class APIClient {
    public void sendReport(String payload, String merchantId, String certSerial) {
        HttpPost request = new HttpPost(REPORT_URL);

        long timestamp = System.currentTimeMillis() / 1000;
        String nonce = java.util.UUID.randomUUID().toString().replaceAll("-", "");

        StringBuilder authBuilder = new StringBuilder();
        authBuilder.append("METHOD=").append("\n")
                .append(REPORT_PATH).append("\n")
                .append(timestamp).append("\n")
                .append(nonce).append("\n")
                .append(payload).append("\n");

        String signature = CryptoUtils.generateSignature(authBuilder.toString(), PRIVATE_KEY);

        String authorizationHeader = "WECHATPAY2 mchid=\"" + merchantId + "\",nonce_str=\"" + nonce + "\","+
                "signature=\"" + signature + "\",timestamp=\"" + timestamp + "\","+
                "serial_no=\"" + certSerial + "\"";

        request.setHeader("Authorization", authorizationHeader);
        request.setHeader("Content-Type", "application/json");
        request.setHeader("User-Agent", "WeChat-Partner-Client/1.0");

        StringEntity entity = new StringEntity(payload, StandardCharsets.UTF_8);
        request.setEntity(entity);
        
        // Execute request logic here
    }
}

Operational Considerations

Several configuration pitfalls frequently occur during integration. Ensure the correct APIv3 key corresponds to the specific environment being accessed. Whitelist status must be verified with the WeChat partner team prior to deployment to prevent decryption failures. Parameter formatting must align exactly with expectations to avoid signature mismatches. Validate that all certificates are current and contain no whitespace artifacts before embedding them into the codebase.

Tags: WeChat API Java Security Encryption rest client Authentication

Posted on Tue, 27 Oct 2026 16:38:39 +0000 by fr@nkie