Packages

Elixir client library for cryptocurrency exchanges — generated from CCXT specs via compile-time macros.

Current section

Files

Jump to
ccxt_client lib ccxt ws auth direct_hmac_expiry.ex
Raw

lib/ccxt/ws/auth/direct_hmac_expiry.ex

defmodule CCXT.WS.Auth.DirectHmacExpiry do
@moduledoc """
Direct HMAC Expiry authentication pattern (Bybit, Bitmex style).
Signs payload: GET/realtime + expires timestamp
Message format: op/args with apiKey, expires, signature
## Example Auth Message (Bybit)
%{
"op" => "auth",
"args" => ["apiKey123", 1699999999999, "signature_hex"]
}
"""
@behaviour CCXT.WS.Auth.Behaviour
alias CCXT.Signing
@default_expires_offset_ms 10_000
@impl true
def pre_auth(_credentials, _config, _opts) do
{:ok, %{}}
end
@impl true
def build_auth_message(credentials, config, _opts) do
api_key = credentials.api_key
secret = credentials.secret
# Calculate expires timestamp
expires_offset = config[:expires_offset_ms] || @default_expires_offset_ms
expires = Signing.timestamp_ms() + expires_offset
# Build payload: GET/realtime{expires}
payload = "GET/realtime#{expires}"
# Sign and encode
signature_raw = Signing.hmac_sha256(payload, secret)
signature =
case config[:encoding] do
:base64 -> Signing.encode_base64(signature_raw)
_ -> Signing.encode_hex(signature_raw)
end
# Build message
op_field = config[:op_field] || "op"
op_value = config[:op_value] || "auth"
message = %{
op_field => op_value,
"args" => [api_key, expires, signature]
}
{:ok, message}
end
@impl true
def handle_auth_response(response, _state) do
cond do
response["success"] == true ->
:ok
response["ret_msg"] && String.contains?(response["ret_msg"], "error") ->
{:error, {:auth_failed, response["ret_msg"]}}
true ->
{:error, {:auth_failed, response}}
end
end
end