WebSocket Authentication

  • 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 + requestPath

Where:

Long timestamp = System.currentTimeMillis();
  • method is always GET
  • requestPath is 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);
        }
    }

}