Authentication and Signature
Overview
To ensure security and data integrity, the OSL API uses an HMAC-SHA256 signature mechanism. Every private request must include specific authentication headers and a valid signature. Requests that fail validation will be rejected.
HTTP Headers
All authenticated requests must include the following headers:
| Header Name | Required | Description |
|---|---|---|
ACCESS-KEY | Yes | The API key assigned to you. |
ACCESS-SIGN | Yes | The generated HMAC-SHA256 signature (note that this is not the API secret, it must be processed). |
ACCESS-TIMESTAMP | Yes | The Unix timestamp of the request in milliseconds. |
ACCESS-PASSPHRASE | Yes | The passphrase you set during API key creation. |
Timestamp Rules
- Format: Must be a Unix timestamp in milliseconds (e.g.,
1766066126559). - Synchronization: The platform validates the request time window. Ensure your server clock is synchronized via a standard NTP server.
Signature Generation
Algorithm
- Type: HMAC-SHA256.
- Encoding: The final result must be Base64 encoded.
String-to-Sign Structure
Concatenate the following fields in this exact order:
timestamp + HTTP_METHOD + request_path + query_string + request_body
| Component | Description |
|---|---|
timestamp | Unix timestamp in milliseconds. |
HTTP_METHOD | The HTTP method in uppercase (e.g., GET, POST). |
request_path | The path portion of the URL excluding the domain (e.g., /api/v2/trade/order). |
query_string | The raw query string including the ? (e.g., ?symbol=BTCUSDT). |
request_body | The raw JSON string of the request body. For requests without a body (e.g., GET), use an empty string. |
Please note that due to the above requirements, the "Try It" console requires a manually generated HMAC signature.
Signature Generation Code Examples
import org.springframework.util.StringUtils;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
public class ApiExample {
// Replace with your own credentials
static final String BASE_URL = "https://api.osl.com";
static final String ACCESS_KEY = "<your-access-key>";
static final String SECRET_KEY = "<your-secret-key>";
static final String PASSPHRASE = "<your-passphrase>";
static final HttpClient HTTP_CLIENT = HttpClient.newHttpClient();
public static void main(String[] args) throws Exception {
queryReqIp();
queryOrder();
}
static void queryReqIp() throws Exception {
apiReq("GET", "/openapi/v1/ip", null, null);
}
static void queryOrder() throws Exception {
apiReq("GET", "/openapi/v1/openOrders", null, null);
}
static void apiReq(String method, String path, String query, String body) throws Exception {
String timestamp = String.valueOf(System.currentTimeMillis());
String sign = sign(timestamp, method, path, query, body);
String url = BASE_URL + path + (StringUtils.hasText(query) ? "?" + query : "");
HttpRequest.Builder builder = HttpRequest.newBuilder()
.uri(URI.create(url))
.header("ACCESS-KEY", ACCESS_KEY)
.header("ACCESS-SIGN", sign)
.header("ACCESS-TIMESTAMP", timestamp)
.header("ACCESS-PASSPHRASE", PASSPHRASE);
switch (method.toUpperCase()) {
case "GET":
builder.method("GET", HttpRequest.BodyPublishers.noBody());
break;
case "POST":
case "DELETE":
builder.header("Content-Type", "application/json")
.method(method.toUpperCase(), HttpRequest.BodyPublishers.ofString(body != null ? body : ""));
break;
}
System.out.println(HTTP_CLIENT.send(builder.build(), HttpResponse.BodyHandlers.ofString()).body());
}
static String sign(String timestamp, String method, String path, String query, String body) throws Exception {
StringBuilder sb = new StringBuilder();
sb.append(timestamp).append(method.toUpperCase()).append(path);
if (query != null && !query.isEmpty()) {
sb.append("?").append(query);
}
if (body != null && !body.isEmpty()) {
sb.append(body);
}
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(SECRET_KEY.getBytes(StandardCharsets.UTF_8), "HmacSHA256"));
return Base64.getEncoder().encodeToString(mac.doFinal(sb.toString().getBytes(StandardCharsets.UTF_8)));
}
}const CryptoJS = require('crypto-js');
const secret = pm.environment.get('API-SECRET');
const apiKey = pm.environment.get('API-KEY');
const apiPassphrase = pm.environment.get('API-PASSPHRASE');
const method = pm.request.method.toUpperCase();
const path = pm.request.url.getPath();
const query = pm.request.url.getQueryString();
const rawBody = pm.request.body?.raw || '';
const timestamp = Date.now().toString();
const stringToSign = timestamp + method + path +
(query ? '?' + query : '') +
rawBody;
console.log('String to sign:', stringToSign);
// Generate HMAC SHA256 signature
const signature = CryptoJS.HmacSHA256(stringToSign, secret);
const accessSign = CryptoJS.enc.Base64.stringify(signature);
// Set the headers
pm.request.headers.add({
key: 'ACCESS-KEY',
value: apiKey
});
pm.request.headers.add({
key: 'ACCESS-SIGN',
value: accessSign
});
pm.request.headers.add({
key: 'ACCESS-TIMESTAMP',
value: timestamp
});
pm.request.headers.add({
key: 'ACCESS-PASSPHRASE',
value: apiPassphrase
});
// Debug output (optional)
console.log('ACCESS-SIGN:', accessSign);
console.log('Request headers info:', pm.request.headers);