Implementing HMAC-SHA256 Authentication for OKEx V5 REST Endpoints in C#

The OKEx V5 authentication protocol requires generating a cryptographic signature for every REST API call. The signature is derived by concatenating the ISO 8601 timestamp, HTTP method, request path, and request body (if applicable). This combined string is hashed using the HMAC-SHA256 algorithm with the API secret key, and the resulting byte sequence is Base64-encoded.

Cryptographic Signature Generation

The following implementation encapsulates the hashing logic. It handles UTF-8 encoding, computes the HMAC-SHA256 hash, and returns the Base64 representation required by the exchange headers.

public static class OkxAuthenticator
{
    public static string GenerateSignature(string timestamp, string httpMethod, string requestPath, string requestBody, string secretKey)
    {
        var prehashPayload = $"{timestamp}{httpMethod.ToUpperInvariant()}{requestPath}{requestBody}";
        var keyBuffer = Encoding.UTF8.GetBytes(secretKey);
        var payloadBuffer = Encoding.UTF8.GetBytes(prehashPayload);

        using var hasher = new HMACSHA256(keyBuffer);
        var computedHash = hasher.ComputeHash(payloadBuffer);
        return Convert.ToBase64String(computedHash);
    }

    public static string GetIsoTimestamp() =>
        DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ss.fffZ", CultureInfo.InvariantCulture);
}

Authenticated HTTP Client Structure

Rather than constructing headers manually for each endpoint, a dedicated client class streamlines the process. This example utilizes Flurl.Http to manage request configuration and header injection.

public class OkxRestClient
{
    private readonly string _accessKey;
    private readonly string _secretKey;
    private readonly string _passphrase;
    private const string BaseUri = "https://www.okex.com";

    public OkxRestClient(string accessKey, string secretKey, string passphrase)
    {
        _accessKey = accessKey;
        _secretKey = secretKey;
        _passphrase = passphrase;
    }

    private async Task<string> SendAuthenticatedAsync(string method, string endpoint, string body = "", CancellationToken ct = default)
    {
        var currentTime = OkxAuthenticator.GetIsoTimestamp();
        var signature = OkxAuthenticator.GenerateSignature(currentTime, method, endpoint, body, _secretKey);

        var request = BaseUri.AppendPathSegment(endpoint)
            .WithHeader("OK-ACCESS-KEY", _accessKey)
            .WithHeader("OK-ACCESS-SIGN", signature)
            .WithHeader("OK-ACCESS-TIMESTAMP", currentTime)
            .WithHeader("OK-ACCESS-PASSPHRASE", _passphrase)
            .WithHeader("Content-Type", "application/json");

        return method.ToUpperInvariant() switch
        {
            "GET" => await request.GetStringAsync(ct),
            "POST" => await request.PostStringAsync(body, ct).ReceiveString(),
            _ => throw new ArgumentException($"Unsupported HTTP verb: {method}")
        };
    }
}

Retrieving Market Tickers (Read-Only Permission)

Market data endpoints require only read-level API permissions. The client method can be invoked to fetch perpetual swap tickers without a request body.

public async Task<string> FetchPerpetualTickersAsync(CancellationToken ct = default)
{
    const string path = "/api/v5/market/tickers?instType=SWAP";
    return await SendAuthenticatedAsync("GET", path, ct: ct);
}

Querying Historical Trade Fills (Trade Permission Required)

Accessing account-specific execution history mandates trade-level permissions. The same authentication flow applies, targeting the fills history route with the spot instrument type parameter.

public async Task<string> QuerySpotFillHistoryAsync(CancellationToken ct = default)
{
    const string path = "/api/v5/trade/fills-history?instType=SPOT";
    return await SendAuthenticatedAsync("GET", path, ct: ct);
}

Both methods return the raw JSON response from the exchange. Error handling for network failures or HTTP status codes (e.g., 401 for invalid signatures, 429 for rate limits) should be implemented around the Flurl calls in production environments.

Tags: C# OKEx API HMAC-SHA256 rest client Flurl.Http

Posted on Sat, 24 Oct 2026 16:14:03 +0000 by badman