Signature
Signature
Copied from Development specification section 4. appSecret never belongs in a client package or a public repository.
Parameter order
Build the signing source string: concatenate time, nonce, and appSecret as key-value pairs in the order time → nonce → appSecret, separated by English commas (UTF-8 encoding):
signing source string = time:{time},nonce:{nonce},appSecret:{appSecret}
Obtain
appSecretfrom Console → My Apps → App Info.
time and nonce must be the same values you put in system. Request body layout: Request conventions.
Secret boundary
appSecret is only used on your server to derive password and sign. Do not send appSecret in params. Do not copy a sample sign into production.
Hash and sign
- Derive the signing key
password: compute SHA-256 ofappSecret, then convert the result to a lowercase hexadecimal string:
password = LowerCase(Hex(SHA-256(appSecret)))
- Calculate
sign: usepasswordas the key, apply HMAC-SHA256 to the signing source string, then Base64-encode the result:
sign = Base64(HMAC-SHA256(signing source string, password))
Code sample (Java)
import org.apache.commons.codec.digest.DigestUtils;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.text.MessageFormat;
import java.time.Instant;
import java.util.Base64;
import java.util.UUID;
/**
* Example: calculate sign
*/
// 1. Current timestamp (UTC, seconds)
Long time = Instant.now().getEpochSecond();
// 2. Random nonce
String nonce = UUID.randomUUID().toString();
// 3. Use the real appSecret from Console → My Apps. The value below is an example only.
String appSecret = "test123456789test123456789";
// 4. Build the signing source string
String SIGN_TEMPLATE = MessageFormat.format(
"time:{0},nonce:{1},appSecret:{2}", time.toString(), nonce, appSecret);
// 5. Derive password = LowerCase(Hex(SHA-256(appSecret)))
String password = DigestUtils.sha256Hex(appSecret).toLowerCase();
// 6. Calculate sign = Base64(HMAC-SHA256(SIGN_TEMPLATE, password))
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(password.getBytes(StandardCharsets.UTF_8), "HmacSHA256"));
byte[] digest = mac.doFinal(SIGN_TEMPLATE.getBytes(StandardCharsets.UTF_8));
String sign = Base64.getEncoder().encodeToString(digest);
Worked example
You can verify locally with the fixed inputs below. If your result matches the case, the calculation is correct.
| Input | Value |
|---|---|
| time | 1706511734 |
| nonce | f5a1ae2d-c09c-4d39-a744-83a5c2c653c2 |
| appSecret | test123456789test123456789 |
Step 1 — Signing source string:
time:1706511734,nonce:f5a1ae2d-c09c-4d39-a744-83a5c2c653c2,appSecret:test123456789test123456789
Step 2 — Derived password:
1f2da89b2fab404859f02bcc80e8521bc7a63af3e5b1da5318f7cf7c56836b09
Step 3 — Calculated sign:
xjhCQBoJ9hRDsCjyDcHjtDNzRZ3ZJezcawsfWeiaoxU=
Common signature failures
| Symptom | What the specification already says |
|---|---|
SN1005 | nonce reused within 5 minutes |
| Time rejected | system.time is UTC seconds; skew must stay within 5 minutes |
| Sign does not match the worked example | Field order must be time → nonce → appSecret; password is lowercase hex SHA-256; HMAC key is that password string |
Copied sample sign | Recalculate every request |
Other result.code values: Return codes.
