401 unauthorized for /api/v3/brokerage/orders

Hi,
I’m getting a 401 Unauthorized response from POST /api/v3/brokerage/orders, when trying to create a trade.
Any idea why?

I think it’s generating the signing header correctly, as the exact same code works fine for GET /api/v3/brokerage/orders.

The API key has all the permissions ticked, including ‘wallet:trades:create’ which I presume (but am not sure) would be one of the ones it needs to do this?

this is the code I’m using that returns 401 Unauthorized

const axios = require('axios')
const crypto = require('crypto');

async function main() {

  // create the json request object
  const cb_access_timestamp = (Date.now() / 1000).toFixed(0); // in ms
  const secret = process.env.COINBASE_API_SECRET
  const requestPath = '/api/v3/brokerage/orders'; 
  const orderData = {
    "client_order_id": "e4f22d85-9117-4fc9-bc7f-6704a21ee98c",
    "product_id": "BTC-GBP",
    "side": "BUY",
    "order_configuration": {
      "market_market_ioc": {
        "quote_size": "1.00"
      }
    }
  }
  const body = JSON.stringify(orderData);
  const method = 'POST';

  // create the prehash string by concatenating required parts
  var message = cb_access_timestamp + method + requestPath + body;
  console.log(message + '\n');

  // create a sha256 hmac with the secret
  var hmac = crypto.createHmac('sha256', secret);

  // sign the require message with the hmac and base64 encode the result
  var cb_access_sign = hmac.update(message).digest('hex');
  
  let config = {
    method: method,
    url: 'https://api.coinbase.com' + requestPath,
    headers: { 
      'Content-Type': 'application/json',
      'CB-ACCESS-KEY': process.env.COINBASE_API_KEY,
      'CB-ACCESS-TIMESTAMP': cb_access_timestamp,
      'CB-ACCESS-SIGN': cb_access_sign,
      'CB-VERSION': '2016-02-18'
    },
    body: body
  };

  axios(config)
  .then((response) => {
    console.log(JSON.stringify(response.data, undefined, 2));
  })
  }
  
  main().catch(console.error);

and like I say, this code works fine to get accounts, which is almost the same apart from the method being ‘GET’ rather than ‘POST’, and the body being blank:

const axios = require('axios')
const crypto = require('crypto');

async function main() {

  // create the json request object
  const cb_access_timestamp = (Date.now() / 1000).toFixed(0); // in ms
  const secret = process.env.COINBASE_API_SECRET
  const requestPath = '/api/v3/brokerage/accounts';
  const body = '';
  const method = 'GET';

  // create the prehash string by concatenating required parts
  var message = cb_access_timestamp + method + requestPath + body;

  // create a sha256 hmac with the secret
  var hmac = crypto.createHmac('sha256', secret);

  // sign the require message with the hmac and base64 encode the result
  var cb_access_sign = hmac.update(message).digest('hex');
  
  let config = {
    method: method,
    url: 'https://api.coinbase.com' + requestPath,
    headers: { 
      'Content-Type': 'application/json',
      'CB-ACCESS-KEY': process.env.COINBASE_API_KEY,
      'CB-ACCESS-TIMESTAMP': cb_access_timestamp,
      'CB-ACCESS-SIGN': cb_access_sign,
      'CB-VERSION': '2016-02-18'
    }
  };

  axios(config)
  .then((response) => {
    console.log(JSON.stringify(response.data, undefined, 2));
  })
  }
  
  main().catch(console.error);

1 Like

You are not actually sending body, are you? You only use body in signature, but you need to POST it too…

Hey I just realised the same thing - good spot

But alas I have edited it and still returns 401 Unauthorized

Will update

1 Like

just realised what it is - it’s an axios error
related to what you said
but it should be

data: body
rather than
body: body

I will leave it here for info in case anybody else gets tripped up by the same

thanks

3 Likes