I'm trying to encrypt a string to HMAC SHA256 within raw javascript using a web-hosted library but it doesn't seem to work. I'm trying to do this to call the Coinbase API. You need to give a few values with the GET request including a Signature, which is where I am experiencing problems. The signature needs to be HMAC SHA256 encrypted. The signature should include the following:
The
CB-ACCESS-SIGN
header is generated by creating a sha256 HMAC using the secret key on the prehash stringtimestamp + method + requestPath + body
(where + represents string concatenation). The timestamp value is the same as theCB-ACCESS-TIMESTAMP
header.The
body
is the request body string or omitted if there is no request body (typically for GET requests).The
method
should be UPPER CASE.
What I think they are saying is that I can leave out the body because it's a GET request.
My code is the following:
The HTML library call:
<script src="https://cdnjs.cloudflare.com/ajax/libs/js-sha256/0.9.0/sha256.js"></script>
The Javascript Encryption and GET request:
url = "https://api.coinbase.com/v2/accounts"
var xmlHttp1 = new XMLHttpRequest();
xmlHttp1.open( "GET", "https://api.coinbase.com/v2/time", false);
xmlHttp1.send( null )
ts = xmlHttp1.responseText;
var ts1 = JSON.parse(ts)
var message = ts1.data.epoch + "GET" + url + ""
sha256(message);
var hash = sha256.hmac.create('key');
var xmlHttp = new XMLHttpRequest();
xmlHttp.open( "GET", url, false ); // false for synchronous request
xmlHttp.setRequestHeader("CB-ACCESS-KEY", "XXXXXXXXXXXXXXXX");
xmlHttp.setRequestHeader("CB-ACCESS-TIMESTAMP", ts1.data.epoch);
xmlHttp.setRequestHeader("CB-ACCESS-SIGN", hash);
xmlHttp.send( null );
The coinbase API is responding with:
{"errors":[{"id":"authentication_error","message":"invalid signature"}]}
meaning that everything is correct, except for the signature.
I was able to figure it out myself (Yunhai also saw 1 of the problems).
The problems were:
The HMAC encryption needed my API_SECRET
I needed to use the URL Parameters, not the entire URL.