John Galassi
John Galassi

Reputation: 318

API0005 Invalid Signature Connection Error from Google Apps Script to BitStamp API

I'm trying to display different pieces of information from my BitStamp account onto a Google Spreadsheet. In order to do that Google Apps Script (GAS) is employed, with Javascript of course.

The error I get is a API0005 which, as you can see from BitStamp API reference page, stands for invalid signature:

API0005    Invalid signature    Posted signature doesn't match with ours

Now, I've been gathering info from several sources, especially here on Stack, but can't quite figure out where the problem is.

There's something I noticed though, which I would like to highlight, as I guess the problem could have to do with that:

For ease of construction I use to append the main steps of the signature synthesis process onto the spreadsheet itself, so to have a better understanding of its development.

You will notice small changes in the nonce output even between a line of code and the next, each time the funcion is somehow called or invoked; and this doesnt surprise me because I guess that everytime nonce is called some milliseconds have passed and the output must be different (after all it was purposely designed for that reason I guess).

But my first concern is: is it ok that it changes even when the toUpperCase() conversion is called? (And by the way this shouldn't be the cause of the problem anyway I guess)

Spreadsheet Cells Screenshot

var nonce = new (function() {
    this.generate = function() {
        var now = Date.now();
        this.counter = (now === this.last? this.counter + 1 : 0);
        this.last    = now;
        // add padding to nonce
        var padding = 
            this.counter < 10 ? '000' : 
                this.counter < 100 ? '00' :
                    this.counter < 1000 ?  '0' : '';
        return now+padding+this.counter;
    };
})();

//funzione write
function write() {

var cred = {
       id:'digit2118',
      key:'2RhZfUKIYJbT8CBYk6T27uRSF8Gufre',
   secret:'T8CBYk6T274yyR8Z2RhZfUxbRbmZZHJ'
};

//adding some cells output to monitor each step of the "conversion" 
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
var cell = sheet.getRange("B14");
cell.setValue(cred.id);
// .. and so on, see screen cap..

var message = nonce.generate() + cred.id +  cred.key;

var res = Utilities.computeHmacSha256Signature(cred.secret, message).map(function(e) {return ("0" + (e < 0 ? e + 256 : e).toString(16)).slice(-2)}).join("");
var signature = res.toUpperCase();

// qui mettiamo i dati per fare la comunicazione vera e propria
var data = {
  key: cred.key,
  signature: res,
  nonce: nonce.generate()
};

var options = {
  'method' : 'post',
  //'contentType': 'application/json',
  // Convert the JavaScript object to a JSON string.
  //'payload' : JSON.stringify(data)
  'muteHttpExceptions' : true,
  'payload' : data
};

var risposta = UrlFetchApp.fetch('https://www.bitstamp.net/api/v2/balance/', options);
  var risposta2 = JSON.parse(risposta.getContentText());

  Logger.log(risposta2);
  //Logger.log(risposta.getContentText()); 
return signature;
}//end of write();

Logger.log(write());

So in the end I can't see where, but that must be something I am missing.

(ps:this is where I got the Nonce code from: Generate Nonce,)

   

EDIT: Question Solved.

Updated code with problem & solution below.

Thanks to @Tanaike

Upvotes: 1

Views: 705

Answers (2)

John Galassi
John Galassi

Reputation: 318

After incorporating the wise suggestion provided by @Tanaike, i.e. to correctly switch value and key in the Utilities.computeHmacSha256Signature(value, key) command, things didn't work yet and I still used to get an Invalid Signature API0005 error.

Long story short, the problem was another oversight in the code:

I correctly switched the signature into toUpperCase() but when it came to send the array to BitStamp, I used to send the lowercase version, which was res instead of signature:

var signature = res.toUpperCase();

// qui mettiamo i dati per fare la comunicazione vera e propria
var data = {
  key: cred.key,
  signature: res,
  nonce: nonce.generate()
};

The detail has been fixed and now it's working fine! This is the complete and updated working code, for your consideration:

//funzione write
function write() {

/* nuova funzione nonce */
_generateNonce = function() {
  var now = new Date().getTime();

  if(now !== this.last)
    this.nonceIncr = -1;

  this.last = now;
  this.nonceIncr++;

  // add padding to nonce incr
  // @link https://stackoverflow.com/questions/6823592/numbers-in-the-form-of-001
  var padding =
    this.nonceIncr < 10 ? '000' :
      this.nonceIncr < 100 ? '00' :
        this.nonceIncr < 1000 ?  '0' : '';
  return now + padding + this.nonceIncr;
}

 var nonce = this._generateNonce(); //fine funzione

var cred = {
       id:'digit2118',
      key:'2RhZfUKIYJbT8CBYk6T27uRSF8Gufrer',
   secret:'T8CBYk6T274yyR8Z2RhZfUxbRbmZZHJr'
};

var message = nonce + cred.id +  cred.key;

var res = Utilities.computeHmacSha256Signature(message, cred.secret).map(function(e) {return ("0" + (e < 0 ? e + 256 : e).toString(16)).slice(-2)}).join("");

var signature = res.toUpperCase();

var data = {
  key: cred.key,
  signature: signature,
  nonce: nonce
};

var options = {
  'method' : 'post',
  //'contentType': 'application/json',
  // Convert the JavaScript object to a JSON string.
  //'payload' : JSON.stringify(data)
  'muteHttpExceptions' : true,
  'payload' : data
};

var risposta = UrlFetchApp.fetch('https://www.bitstamp.net/api/v2/balance/', options);
  var risposta2 = JSON.parse(risposta.getContentText());
  var risposta3 = risposta2['usd_balance'];
  Logger.log(risposta3);
return signature;
}//end of write();

Upvotes: 0

Tanaike
Tanaike

Reputation: 201378

How about this modification?

Modification points:

  • At the arguments of Utilities.computeHmacSha256Signature(value, key), it's value and key in order.
    • Please modify Utilities.computeHmacSha256Signature(cred.secret, message) to Utilities.computeHmacSha256Signature(message, cred.secret).

Modified script:

From:
var res = Utilities.computeHmacSha256Signature(cred.secret, message).map(function(e) {return ("0" + (e < 0 ? e + 256 : e).toString(16)).slice(-2)}).join("");
To:
var res = Utilities.computeHmacSha256Signature(message, cred.secret).map(function(e) {return ("0" + (e < 0 ? e + 256 : e).toString(16)).slice(-2)}).join("");

Note:

  • If an error occurs after above modification, please fix nonce as a constant value in a request and try again.
    • I think that nonce might be required to be fixed in a request. About this, please test at your environment.
    • Because when I saw a sample script for Node.js, nonce was fixed as a constant value in a request.

Reference:

I cannot test this modification in my environment. So if this was not the directly solution for your issue, I apologize. If an error message was changed by this modification, also please provide it.

Upvotes: 1

Related Questions