Search code examples
bashcurlcoinbase-api

Coinbase Sandbox API /accounts call - Invalid Signature with curl


Greets,

Looks like I'm having a similar problem to others (here and here), but seem to be missing something obvious. Trying to call Coinbase Sandbox API /accounts to get a list of accounts. Literally the most basic call to get into this...

Following the SIGN docs at docs.cloud.coinbase.com

To understand the problem, I'm using stock standard BASH script with a curl call:

#!/usr/bin/env bash

TS=$(date +%s)
API_KEY=fbb28bed4617217f482d878770b8c9b7
PASSPHRASE="passphrase87867"
SECRET="apcep9z66jyW3koh5uHhnq0hKQ5q59EBgTtpZ/GsvN9aigrFbxMpuz+YP7xXo/ev+OBZpqmv4OpCk7OKx6qGbw=="
URL="https://api-public.sandbox.exchange.coinbase.com/accounts"
#https://api.exchange.coinbase.com/accounts \
#https://api-public.sandbox.pro.coinbase.com/accounts \

SIG=$(echo "${TS}GET/accounts" | hmac256 --binary $API_KEY | base64)
#SIG=$(echo "${TS}GET/accounts" | hmac256 --binary $SECRET | base64)
#also tried with PASSPHRASE & SECRET and without base64:
#SIG=$(echo "${TS}GET/accounts" | hmac256 $PASSPHRASE)
#SIG=$(echo "${TS}GET/accounts" | hmac256 $SECRET)

curl --request GET \
     --url $URL \
     --header 'Accept: application/json' \
     --header "cb-access-key: $API_KEY" \
     --header "cb-access-passphrase: $PASSPHRASE" \
     --header "cb-access-sign: $SIG" \
     --header "cb-access-timestamp: $TS"

#comments indicate various settings I've tried.

I just keep getting the {"message":"invalid signature"} error.

I'd appreciate any pointers.

/update: This page contains a way to calculate the signature (binance, yes, I get the irony): https://binance-docs.github.io/apidocs/spot/en/#signed-trade-user_data-and-margin-endpoint-security :

echo -n "symbol=LTCBTC&side=BUY&type=LIMIT&timeInForce=GTC&quantity=1&price=0.1&recvWindow=5000&timestamp=1499827319559" | openssl dgst -sha256 -hmac "NhqPtmdSJYdKjVHjA7PZj4Mge3R5YNiP1e3UZjInClVN65XAbvqqM6A7H5fATj0j"

Thanks


Solution

  • For completeness sake, here's the C# solution:

    using RestSharp;
    using System.Text;
    using System.Security.Cryptography;
    using System.Globalization;
    
    string computeSignature(
            HttpMethod httpMethod,
            string secret,
            double timestamp,
            string requestUri,
            string contentBody = "")
    {
        var convertedString = System.Convert.FromBase64String(secret);
        var prehash = timestamp.ToString("F0", CultureInfo.InvariantCulture) + httpMethod.ToString().ToUpper() + requestUri + contentBody;
        return hashString(prehash, convertedString);
    }
    
    string hashString(string str, byte[] secret)
    {
        var bytes = Encoding.UTF8.GetBytes(str);
        using (var hmaccsha = new HMACSHA256(secret))
        {
            return System.Convert.ToBase64String(hmaccsha.ComputeHash(bytes));
        }
    }
    
    var timeStamp = DateTimeOffset.Now.ToUnixTimeSeconds();
    var apiKey = "fbb28bed4617217f482d878770b8c9b7";
    var passPhrase = "passphrase87867";
    var secret = "apcep9z66jyW3koh5uHhnq0hKQ5q59EBgTtpZ/GsvN9aigrFbxMpuz+YP7xXo/ev+OBZpqmv4OpCk7OKx6qGbw==";
    var URL = "https://api-public.sandbox.exchange.coinbase.com/accounts";
    
    var client = new RestClient(URL);
    var request = new RestRequest();
    request.AddHeader("Accept", "application/json");
    request.AddHeader("cb-access-key", apiKey);
    request.AddHeader("cb-access-passphrase", passPhrase);
    request.AddHeader("cb-access-sign", computeSignature(HttpMethod.Get, secret, timeStamp, "/accounts"));
    request.AddHeader("cb-access-timestamp", timeStamp);
    RestResponse response = client.Execute(request);
    // ...