1

I hope you have more luck on this than I have.

As the title suggests I am trying to hit a private API endpoint on bitstamp.net. https://www.bitstamp.net/api/#api-authentication try as I might I cannot get the signature to make sense. I have followed the docs as close as I know how, I have spent hours trying to learn as much python as possible and decyphering the docs, as there is no JavaScript example.

The signature is supposed to be a sha256 hmac of the API secret and the message variable which is a backslash seperated string that I cannot find anything wrong with anymore.

I use the below link to query the server, the apikey and secret will be encoded and decoded in production when this all works.

http://localhost:3001/sha256/jorw1007/QGcJKrhenfqOML5cOpTsLOe9IbEPsJnN/bKXiqtYHawJ7DAUZIHviAPoRrp0zhfIv

 const crypto = require('crypto'); app.get("/sha256/:id/:key/:secret", cors(), (request, response, next) => { const APIkey = "BITSTAMP" + " " + request.params.key; const APIsecret = request.params.secret; const urlHost = "192.168.0.120:3001"; // where is querying the API from bitstamp? in this case its the server localhost:3001 const urlPath = "/api/v2/balance/"; const urlQuery = ""; const UTC = Date.now().toString(); const nonce = randomBytes(18).toString("hex").toLowerCase(); const nonce2 = "f93c979d-b00d-43a9-9b9c-fd4cd9547fa6" const contentType = "application/x-www-form-urlencoded"; const version = "v2"; const payload = urlencoded({"offset": "1"}) let message = `${APIkey}\\POST\\${urlHost}\\${urlPath}\\${urlQuery}\\${nonce}\\${UTC}\\${version}\\` // const encodedMsg = encodeURI(message) ///why are we encoding? // const signature = createHmac("sha256", APIsecret ).update(JSON.stringify(encodedMsg) ); // const sigDigested = signature.digest('hex') var signature = crypto.createHmac('sha256', APIsecret).update(encodeURI(message)); // to lowercase hexits const digestedHash = signature.digest('hex'); console.log(message) const headers = { "X-Auth": APIkey, "X-Auth-Signature": digestedHash, "X-Auth-Nonce": nonce, "X-Auth-Timestamp": UTC, "X-Auth-Version": version, }; fetch("https://www.bitstamp.net/api/v2/balance/", { headers, method: "POST", data : payload }) .then((res) => res.json()) .then((json) => response.send(json)) .catch((err) => console.error(err)); }); 

I keep getting error 'API0005' which means the signature is invalid.

Please could someone point me in the right direction?

thank you

2
  • Have you had any luck with this? Facing the smae issue. Commented Aug 20, 2021 at 19:30
  • Same issue, beginning to think the issue is on their end Commented Aug 26, 2021 at 5:36

1 Answer 1

3

After countless effort I finally managed to get it work. The code I will be posting is in C# but it very much resembles that of JavaScript.

protected async Task<string> SendRequest(string @base, string endpoint, EndpointHttpMethod method, Dictionary<string, object> parameters = null, bool signed = true) { var resiliencyStrategy = ExchangeTools.DefineAndRetrieveResiliencyStrategy("Bitstamp"); parameters ??= new Dictionary<string, object>(); var payloadString = string.Empty; var queryParameters = string.Empty; var contentType = string.Empty; if (method == EndpointHttpMethod.GET) { queryParameters = ExchangeTools.BuildQuery(parameters); endpoint += !string.IsNullOrWhiteSpace(queryParameters) ? $"?{queryParameters}" : string.Empty; } else { payloadString = ExchangeTools.BuildQuery(parameters, true); contentType = !string.IsNullOrWhiteSpace(payloadString) ? "application/x-www-form-urlencoded" : string.Empty; } using var client = new HttpClient(); using var httpRequestMessage = new HttpRequestMessage(new HttpMethod(method.ToString()), endpoint); client.BaseAddress = new Uri(Endpoints.BasePrefix + @base); if (signed) { var apiKey = $"BITSTAMP {publicKey}"; var version = "v2"; var nonce = Guid.NewGuid(); var timestamp = ExchangeTools.GetUnixTimestamp(1000); var msg = $"{apiKey}{method}{@base}{endpoint}{queryParameters}{contentType}{nonce}{timestamp}{version}{payloadString}"; var signature = ExchangeTools.Sign(msg, privateKey, HashingAlgorithm.HMACSHA256, ByteEncoding.ASCII, SignatureEncoding.HexString); httpRequestMessage.Headers.Add("X-Auth", apiKey); httpRequestMessage.Headers.Add("X-Auth-Signature", signature); httpRequestMessage.Headers.Add("X-Auth-Nonce", nonce.ToString()); ; httpRequestMessage.Headers.Add("X-Auth-Timestamp", timestamp.ToString()); ; httpRequestMessage.Headers.Add("X-Auth-Version", version); if(parameters.Count > 0) { httpRequestMessage.Content = new FormUrlEncodedContent(parameters.ToDictionary(kv => kv.Key, kv => kv.Value.ToString())); } } var response = await resiliencyStrategy.ExecuteAsync(() => client.SendAsync(httpRequestMessage)); var result = await response.Content.ReadAsStringAsync(); return result; } 

Let me know if you need further clarification. My best guess as to why yours is not working comes down to conditionally setting the payload and queryParam depending on what parameters you have and whether the request is a GET or POST.

Sign up to request clarification or add additional context in comments.

1 Comment

what is the contents of ExchangeTools.Sign method in your response? I think this is the main reason why requests fail with invalid signature response...

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.