Invalid Signature on Wallet endpoints

Hi,
I’m getting an unauthorized “invalid signature” response to all wallet endpoints. But for data endpoints, I’m successful receiving a response 200.
What do you think is the problem? Am I doing something wrong? Appreciate if someone will explain it to me. Btw, I’m using Postman as test bed. Regards

Hello @envi1624! Thank you for taking an interest in trying out Coinbase APIs. Now, before getting started with addressing your concern, we’d like to clear some things out. The data and wallet endpoints have different ways to request an API response.

The data endpoint is a public endpoint which does not need authentication and authorization from the user. However, the wallet endpoint is a private endpoint which must have authentication and authorization. For you to get started, please refer to API key authentication.

If you completed the item mentioned above and still encountered an “invalid signature” error response. Please provide us with a screenshot of your authentication and authorization code snippet. This will surely help us when we check on this for you with our team.

Please let us know if you have any questions. Thank you!

3 Likes

@camille.decastro So I followed your instruction about authentication and authorization, but no luck. I’m still receiving invalid signature response. I copied the Pre-request Script I added to Postman. Please, can you help me to check. Thank you in advance!

pm.collectionVariables.set("coinbase-api-base", "https://api.coinbase.com");
pm.collectionVariables.set("coinbase-api-key", "xxxxxxxxxxxxxx");
pm.collectionVariables.set("coinbase-api-secret", "xxxxxxxxxxxxxxx");
var CryptoJS = require("crypto-js");
var req = {

    timestamp: Math.floor(Date.now()/1000),
    method: pm.request.method,
    path: pm.request.url.getPath(),
    body: (pm.request.method === 'GET' || !data) ? '' : JSON.parse(pm.request.body), 
    message: undefined,
    secret: CryptoJS.enc.Base64.parse(pm.collectionVariables.get("coinbase-api-secret")), 
    hmac: undefined,
    signature: undefined,
};

req.message = req.timestamp + req.method + req.path + req.body;
req.hmac = CryptoJS.HmacSHA256(req.message, req.secret);
req.signature = req.hmac.toString(CryptoJS.enc.Base64);

console.info("request: ", req);
pm.collectionVariables.set("coinbase-api-timestamp", req.timestamp);
pm.collectionVariables.set("coinbase-api-signature", req.signature);

Hello @envi1624, thank you for following up and providing additional details. We will be including the information and the code snippet you’ve provided so our team can look into this and we will get back to you once we have more information. Keep in touch!

Hello @envi1624! Based from the Pre-request script you provided, we had observed two issues that might be causing you the invalid signature response:

  1. The API secret is being parsed as a Base64 which should not be the case for Sign-in-with-Coinbase API and does not need to be decoded
  2. We can see that you’re utilizing Base64 when generating the signature (req.signature = req.hmac.toString(CryptoJS.enc.Base64) which is not needed.

Hence, we recommend that you should not parse the API secret as Base64 and not to utilize Base64 when generating the signature.

The CB-ACCESS-SIGN header is generated by creating **a sha256 HMAC using the secret key on the prehash string timestamp + method + requestPath + body** (where + represents string concatenation). The timestamp value is the same as the CB-ACCESS-TIMESTAMP header. We also have an example for signing the signature var signature = crypto.createHmac("sha256", apiSecret).update(message).digest("hex");. For more information, you may check our API Documentation

Note: Base64 is utilized on the authentication and authorization for Coinbase Pro/Exchange but not for Sign in with Coinbase API.

We hope this helps. Thank you!

3 Likes

Would you mind to share a sample working code? Highly appreciated! Thanks!

Hi @envi1624, here is a sample working code. We tried calling the endpoint v2/user/auth and received an http status code of 200 together with the JSON response that contains the list of permission enabled on the API key.

pm.collectionVariables.set(“coinbase-api-base”, “https://api.coinbase.com”);
pm.collectionVariables.set(“coinbase-api-key”, “xxxxxxxxxxxxxx”);
pm.collectionVariables.set(“coinbase-api-secret”, “xxxxxxxxxxxxxxx”);
// 1. Import crypto-js library
var CryptoJS = require(“crypto-js”);

// 2. Create the JSON request object
var req = {
timestamp: Math.floor(Date.now()/1000), // seconds since Unix epoch
method: pm.request.method,
path: pm.request.url.getPath(),
body: (pm.request.method === ‘GET’ || !data) ? ‘’ : pm.request.body, // empty for GET requests
message: undefined,
secret: pm.collectionVariables.get(“coinbase-api-secret”), // read value from collection variable
hmac: undefined,
signature: undefined,
};

// 3. Create the message to be signed
req.message = req.timestamp + req.method + req.path + req.body;

// 4. Create HMAC using message and API secret
req.hmac = CryptoJS.HmacSHA256(req.message, req.secret);

// 5. Obtain signature by converting HMAC to hexadecimal String
req.signature = req.hmac.toString(CryptoJS.enc.Hex);

// 6. Log the request
console.info("request: ", req);

// 7. Set Postman request’s authentication headers for Coinbase REST API call
pm.collectionVariables.set(“coinbase-api-timestamp”, req.timestamp);
pm.collectionVariables.set(“coinbase-api-signature”, req.signature);

As you can see in the code above, the API secret is not being parsed as a Base64 and the HMAC generated using the secret key is converted to Hexadecimal String instead of Base64.
We hope this helps. Thank you!

5 Likes

@leo.lemuel.federico, working well, thank you Coinbase team!

5 Likes