Authentication
Guide
- Alchemy Pay will issue a pair of merchantCode&privatekey for each partner once onboarded with Alchemy Pay. The merchantCode is used to identify the partner, while privatekey is for signature purposes.
- merchantCode&privatekey will be delivered to the partner upon request from Alchemy Pay's operation team. There is currently no online service for self-apply.
- Under no circumstances expose the privatekey in any API request.
Signature
Mutual authentication is implemented. For requests, the caller needs to compute a digital signature and add the signature as part of the HTTP body. Conversely, for responses, Alchemy Pay provides its signature in the HTTP body in the response. The request signature is generated as follows:
Step | Description | Example |
---|---|---|
1 | Sort all parameters in ascending order according to parameter names | Parameter list: abc=value1 bcd=value2 bad=value3 Sort result: abc=value1 bad=value3 bcd=value2 |
2 | Connect all parameters with '&' with stringA | abc=value1&bad=value3&bcd=value2 |
3 | Combine the stringA with ‘&’with key=privatekey to stringB. key is case sensitive must be with low case | abc=value1&bad=value3&bcd=value&key=privatekey. |
4 | MD5 the stingB with upper case | MD5(stringB).toUpperCase(); |
5 | Save the signature in HTTP body |
Sign demo for Page integration
package com.example;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Base64;
import java.util.TreeMap;
import javax.crypto.Cipher;
import javax.crypto.Mac;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
import java.util.Random;
public class nft {
private final static String CHARSET = "UTF-8";
public static String sign(String s, String key) throws Exception {
Mac mac = Mac.getInstance("HmacSHA1");
SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(CHARSET), mac.getAlgorithm());
mac.init(secretKeySpec);
byte[] hash = mac.doFinal(s.getBytes(CHARSET));
return DatatypeConverter.printBase64Binary(hash);
}
public static void main(String[] args) throws Exception {
final String APP_ID = "ahzxh0klegv1fzol";
final String APP_SECRET = "py2bwighth62ajq6";
String signStr = "amount=3000&appId=ahzxh0klegv1fzol&callbackUrl=https://alchemypay.org&fiat=USD&merchantName=merchantName&merchantOrderNo=ACH100001234&name=nftname&nonce=1862325104&picture=https://download.bit.store/official/BitStore/pic/user_portrait/20.jpeg&redirectUrl=https://alchemypay.org&targetFiat=SGD&timeout=1675394255000×tamp=1675417608&type=MARKET&uniqueId=1113"
String signture = sign(signStr, APP_SECRET); // 公共参数
System.out.println("signture is: " + signture);
}
}
Sign demo for API
public class APISignCheckUtil {
private static final char[] HEX_DIGITS = { '0', '1', '2', '3', '4', '5',
'6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
public static String getMerSign(String appId, String appSecret, String timestamp) {
return encode("sha1", appId + appSecret + timestamp);
}
private static String encode(String algorithm, String value) {
if (value == null) {
return null;
}
try {
MessageDigest messageDigest
= MessageDigest.getInstance(algorithm);
messageDigest.update(value.getBytes());
return getFormattedText(messageDigest.digest());
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private static String getFormattedText(byte[] bytes) {
int len = bytes.length;
StringBuilder buf = new StringBuilder(len * 2);
for (int j = 0; j < len; j++) {
buf.append(HEX_DIGITS[(bytes[j] >> 4) & 0x0f]);
buf.append(HEX_DIGITS[bytes[j] & 0x0f]);
}
return buf.toString();
}
}
Updated 1 day ago