How to Verify WeChat Pay V3 Response Signatures in Java

This guide explains why and how to verify WeChat Pay V3 response signatures using Java, covering certificate serial checks, constructing the verification string from response headers, and performing SHA256‑with‑RSA validation to ensure responses truly originate from the WeChat Pay server.

Programmer DD
Programmer DD
Programmer DD
How to Verify WeChat Pay V3 Response Signatures in Java

1. Introduction

WeChat Pay V3 series previously covered request signing and how to obtain and refresh the platform public key; this article continues by explaining how to verify the signature of WeChat Pay response results.

2. Why Verify Response Signature

WeChat Pay includes a signature in the HTTP response headers. Merchants must verify it to ensure the response truly originates from WeChat Pay servers and to prevent man‑in‑the‑middle attacks. Verification requires the platform public key and additional header parameters.

Example of a WeChat Pay server response:

HTTP/1.1 200 OK
Server: nginx
Date: Tue, 02 Apr 2019 12:59:40 GMT
Content-Type: application/json; charset=utf-8
...
Wechatpay-Nonce: c5ac7061fccab6bf3e254dcf98995b8c
Wechatpay-Signature: CtcbzwtQjN8rnOXItEBJ5aQFSnIXESeV28Pr2YEmf9wsDQ8Nx25ytW6FXBCAFdrr0mgqngX3AD9gNzjnNHzSGTPBSsaEkIfhPF4b8YRRTpny88tNLyprXA0GU5ID3DkZHpjFkX1hAp/D0fva2GKjGRLtvYbtUk/OLYqFuzbjt3yOBzJSKQqJsvbXILffgAmX4pKql+Ln+6UPvSCeKwznvtPaEx+9nMBmKu7Wpbqm/+2ksc0XwjD+xlvlECkCxfD/OJ4gN3IurE0fpjxIkvHDiinQmk51BI7zQD8k1znU7r/spPqB+vZjc5ep6DC5wZUpFu5vJ8MoNKjCu8wnzyCFdA==
Wechatpay-Timestamp: 1554209980
Wechatpay-Serial: 5157F09EFDC096DE15EBE81A47057A7232F1B8E1
...
{"prepay_id":"wx2922034726858082fbd40b511c67630000"}

Check Platform Certificate Serial Number

The response includes a platform certificate serial number in the Wechatpay-Serial header. This indicates which certificate should be used for verification; if the serial is missing, the certificate must be refreshed. The previous article stored the serial‑certificate pairs in a HashMap, so we only need to check its presence.

Construct the Signature String

Three parameters from the response are needed to build the string that will be verified.

/**
 * Build the verification string.
 *
 * @param wechatpayTimestamp timestamp from Wechatpay‑Timestamp header
 * @param wechatpayNonce      nonce from Wechatpay‑Nonce header
 * @param body                response body
 * @return the concatenated string
 */
public String responseSign(String wechatpayTimestamp, String wechatpayNonce, String body) {
    return Stream.of(wechatpayTimestamp, wechatpayNonce, body)
                 .collect(Collectors.joining("
", "", "
"));
}

Verify the Signature

The signature to verify is obtained from the Wechatpay-Signature header. Using the platform public key, we verify the constructed string with SHA256‑with‑RSA.

// Build the verification string
final String signatureStr = responseSign(wechatpayTimestamp, wechatpayNonce, body);
// Load SHA256withRSA signer
Signature signer = Signature.getInstance("SHA256withRSA");
// Initialize with the platform certificate
signer.initVerify(certificate);
// Update signer with the verification string
signer.update(signatureStr.getBytes(StandardCharsets.UTF_8));
// Verify the Base64‑decoded signature from the header
boolean result = signer.verify(Base64Utils.decodeFromString(wechatpaySignature));

Complete Verification Method

/**
 * Verify WeChat Pay response signature using the platform certificate.
 *
 * @param wechatpaySerial    current certificate serial number
 * @param wechatpaySignature signature from Wechatpay‑Signature header
 * @param wechatpayTimestamp timestamp from Wechatpay‑Timestamp header
 * @param wechatpayNonce     nonce from Wechatpay‑Nonce header
 * @param body               response body
 * @return true if verification succeeds
 */
@SneakyThrows
public boolean responseSignVerify(String wechatpaySerial, String wechatpaySignature,
                                 String wechatpayTimestamp, String wechatpayNonce, String body) {
    if (CERTIFICATE_MAP.isEmpty() || !CERTIFICATE_MAP.containsKey(wechatpaySerial)) {
        refreshCertificate();
    }
    Certificate certificate = CERTIFICATE_MAP.get(wechatpaySerial);
    final String signatureStr = createSign(wechatpayTimestamp, wechatpayNonce, body);
    Signature signer = Signature.getInstance("SHA256withRSA");
    signer.initVerify(certificate);
    signer.update(signatureStr.getBytes(StandardCharsets.UTF_8));
    return signer.verify(Base64Utils.decodeFromString(wechatpaySignature));
}
The CERTIFICATE_MAP container for platform certificates is described in the previous article.

3. Summary

Successful verification confirms that the response originates from WeChat Pay, allowing further business logic. Both V2 and V3 APIs require using API certificates for request signing and response verification, which heavily relies on proper use of cryptographic hash algorithms. Mastering this skill gives an edge in interviews and real‑world development.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaRSAAPI SecurityWeChat Paysignature verification
Programmer DD
Written by

Programmer DD

A tinkering programmer and author of "Spring Cloud Microservices in Action"

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.