- Authentication timing: Send the authentication command after the WebSocket connection is established.
- Authentication fields:
apiKey: Unique user identifier used for API calls. The user must apply for this.passphrase: Password for the API Key. If there is no passphrase, pass an empty string ("").timestamp: Unix millisecond timestamp. The timestamp expires after 30 seconds.sign: Signature string. The signature rule is described below.
Signature Rule
The message to be signed is:
timestamp + method + requestPathWhere:
Long timestamp = System.currentTimeMillis();methodis alwaysGETrequestPathis always/user/verify
Signature Generation Steps
Step 1: Encrypt the message using HMAC-SHA256 with the private key secretKey.
Signature = hmac_sha256(secretKey, Message)Step 2: Base64 encode the signature.
Signature = base64.encode(Signature)Authentication Example Code
The authentication data structure follows the format of subscribing to a stream in the public market data API. For private data, the parameter passed in params is the Base64 string of the authentication object.
import com.alibaba.fastjson.JSON;
import okhttp3.*;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.HashMap;
public class WssExample {
// Replace with your own credentials
static final String BASE_URL = "wss://stream-api.osl.com/openapi/v1/ws/user";
static final String ACCESS_KEY = "<your-access-key>";
static final String SECRET_KEY = "<your-secret-key>";
static final String PASSPHRASE = "<your-passphrase>";
public static void main(String[] args) {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url(BASE_URL)
.build();
WebSocket webSocket = client.newWebSocket(request, new WebSocketListener() {
@Override
public void onOpen(WebSocket webSocket, Response response) {
Long timestamp = System.currentTimeMillis();
HashMap<Object, Object> loginParams = new HashMap<>();
loginParams.put("apiKey", ACCESS_KEY);
loginParams.put("passphrase", PASSPHRASE);
loginParams.put("timestamp", timestamp);
loginParams.put("sign", sign(timestamp));
String loginBase64 = Base64.getEncoder().encodeToString(JSON.toJSONString(loginParams).getBytes(StandardCharsets.UTF_8));
String text = "{\"method\":\"SUBSCRIBE\",\"params\":[\"" + loginBase64 + "\"],\"binary\":false}";
webSocket.send(text);
}
@Override
public void onMessage(WebSocket webSocket, String text) {
System.out.println(text);
}
@Override
public void onClosing(WebSocket webSocket, int code, String reason) {
webSocket.close(1000, null);
}
@Override
public void onFailure(WebSocket webSocket, Throwable t, Response response) {
System.out.println(t.getMessage());
}
});
client.dispatcher().executorService().shutdown();
}
static String sign(Long timestamp) {
try {
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(SECRET_KEY.getBytes(StandardCharsets.UTF_8), "HmacSHA256"));
mac.update(String.format("%sGET/user/verify", timestamp).getBytes(StandardCharsets.UTF_8));
return Base64.getEncoder().encodeToString(mac.doFinal());
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}