Use an SDK whenever possible — SDKs handle signing automatically, so you can skip this page. Only implement signing manually if your language or environment is not supported by the available SDKs.
Machine Translation uses Resource Oriented Architecture (ROA)-style API requests authenticated with HMAC-SHA1 signatures. Every request must carry a valid Authorization header. Signing serves three purposes:
Verify your identity — the signature proves the request comes from a holder of valid credentials
Protect data in transit — key request elements are hashed together, so any tampering invalidates the signature
Prevent replay attacks — a unique nonce per request ensures that a captured request cannot be reused
The signature is derived from two components:
Request headers — a canonical string built from selected HTTP headers
CanonicalizedResource — the URI path of the resource you are accessing
Request headers
Each request requires the following headers.
| Header | Required | Value / format |
|---|---|---|
Authorization | Yes | acs <AccessKeyId>:<Signature> |
Content-Type | Yes | application/json;charset=utf-8 |
Content-MD5 | Yes | Base64-encoded MD5 hash of the request body. Include this header on all requests to detect tampering. |
Date | Yes | GMT timestamp, for example: Wed, 26 Aug 2015 17:01:00 GMT |
Accept | Yes | application/json |
Host | Yes | mt.cn-hangzhou.aliyuncs.com |
x-acs-signature-nonce | Yes | A unique random value per request. Prevents replay attacks. |
x-acs-signature-method | Yes | HMAC-SHA1 |
x-acs-version | Yes | API version, for example: 2019-01-02. If omitted, the server uses the latest version. |
Content-Length | No | HTTP request body length as defined in RFC 2616. |
How signing works
Signing turns your request headers and URI into a single string, then produces an HMAC-SHA1 digest of that string using your AccessKeySecret.
Step 1: Hash the request body
Compute the MD5 hash of the request body, Base64-encode the result, and set it as Content-MD5.
Step 2: Build the canonical headers string
Concatenate the following values in order, each followed by \n:
headerStringToSign =
HTTP method + "\n" // Only POST is supported
+ Accept + "\n" // application/json
+ Content-MD5 + "\n" // Value from step 1
+ Content-Type + "\n" // application/json;charset=utf-8
+ Date + "\n" // GMT timestamp
+ "x-acs-signature-method:HMAC-SHA1\n"
+ "x-acs-signature-nonce:" + <nonce> + "\n"
+ "x-acs-version:2019-01-02" + "\n"Step 3: Build the canonical resource string
Set resourceStringToSign to the request URI. All Machine Translation requests have no query parameters, so the value is simply the URI path:
resourceStringToSign = URIIf query parameters were present, they would be sorted lexicographically and appended after ?.
Step 4: Compute the signature
Concatenate the two strings from steps 2 and 3 to form StringToSign:
StringToSign = headerStringToSign + resourceStringToSignCompute the HMAC-SHA1 digest of StringToSign using your AccessKeySecret (RFC 2104), Base64-encode the result, and construct the Authorization header:
Signature = Base64( HMAC-SHA1( AccessSecret, UTF-8-Encoding-Of(StringToSign) ) )
Authorization = "acs " + AccessKeyId + ":" + SignatureJava example
The following example implements all four steps and sends a signed POST request.
package com.alibaba.intl.translate.service.impl.displaytitle;
import java.util.Map;
import jodd.util.Base64;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.security.MessageDigest;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.UUID;
public class Sender {
/**
* Step 1: Compute MD5 hash of the request body and Base64-encode it.
*/
public static String MD5Base64(String s) {
if (s == null)
return null;
String encodeStr = "";
byte[] utfBytes = s.getBytes();
MessageDigest mdTemp;
try {
mdTemp = MessageDigest.getInstance("MD5");
mdTemp.update(utfBytes);
byte[] md5Bytes = mdTemp.digest();
encodeStr = Base64.encodeToString(md5Bytes);
} catch (Exception e) {
throw new Error("Failed to generate MD5 : " + e.getMessage());
}
return encodeStr;
}
/**
* Step 4: Compute HMAC-SHA1 and Base64-encode the result.
*/
public static String HMACSha1(String data, String key) {
String result;
try {
SecretKeySpec signingKey = new SecretKeySpec(key.getBytes(), "HmacSHA1");
Mac mac = Mac.getInstance("HmacSHA1");
mac.init(signingKey);
byte[] rawHmac = mac.doFinal(data.getBytes());
result = Base64.encodeToString(rawHmac);
} catch (Exception e) {
throw new Error("Failed to generate HMAC : " + e.getMessage());
}
return result;
}
/**
* Format a Date as a GMT string for the Date header.
*/
public static String toGMTString(Date date) {
SimpleDateFormat df = new SimpleDateFormat("E, dd MMM yyyy HH:mm:ss z", Locale.UK);
df.setTimeZone(new java.util.SimpleTimeZone(0, "GMT"));
return df.format(date);
}
/**
* Send a signed POST request to the Machine Translation API.
*
* @param url The API endpoint URL
* @param body The JSON request body
* @param ak_id Your AccessKeyId
* @param ak_secret Your AccessKeySecret
* @return The response body as a string
*/
public static String sendPost(String url, String body, String ak_id, String ak_secret) {
PrintWriter out = null;
BufferedReader in = null;
String result = "";
try {
URL realUrl = new URL(url);
// Build request header values
String method = "POST";
String accept = "application/json";
String content_type = "application/json;charset=utf-8";
String path = realUrl.getFile();
String date = toGMTString(new Date());
String host = realUrl.getHost();
// Step 1: Hash the request body
String bodyMd5 = MD5Base64(body);
// Steps 2-3: Build StringToSign
String uuid = UUID.randomUUID().toString();
String stringToSign = method + "\n" + accept + "\n" + bodyMd5 + "\n" + content_type + "\n" + date + "\n"
+ "x-acs-signature-method:HMAC-SHA1\n"
+ "x-acs-signature-nonce:" + uuid + "\n"
+ "x-acs-version:2019-01-02\n"
+ path;
// Step 4: Compute signature and build Authorization header
String signature = HMACSha1(stringToSign, ak_secret);
String authHeader = "acs " + ak_id + ":" + signature;
// Send the request
URLConnection conn = realUrl.openConnection();
conn.setRequestProperty("Accept", accept);
conn.setRequestProperty("Content-Type", content_type);
conn.setRequestProperty("Content-MD5", bodyMd5);
conn.setRequestProperty("Date", date);
conn.setRequestProperty("Host", host);
conn.setRequestProperty("Authorization", authHeader);
conn.setRequestProperty("x-acs-signature-nonce", uuid);
conn.setRequestProperty("x-acs-signature-method", "HMAC-SHA1");
conn.setRequestProperty("x-acs-version", "2019-01-02");
conn.setDoOutput(true);
conn.setDoInput(true);
out = new PrintWriter(conn.getOutputStream());
out.print(body);
out.flush();
// Read the response
InputStream is;
HttpURLConnection httpconn = (HttpURLConnection) conn;
if (httpconn.getResponseCode() == 200) {
is = httpconn.getInputStream();
} else {
is = httpconn.getErrorStream();
}
in = new BufferedReader(new InputStreamReader(is));
String line;
while ((line = in.readLine()) != null) {
result += line;
}
} catch (Exception e) {
System.out.println("Exception sending POST request: " + e);
e.printStackTrace();
} finally {
try {
if (out != null) {
out.close();
}
if (in != null) {
in.close();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
return result;
}
}