Why I still get 'authentication failure' in Coinbase websocket feed?

Hi

I try to send a subscribe message to Coinbase websocket but still get this error (advanced trade API):

{‘type’: ‘error’, ‘message’: ‘authentication failure’}

this is part of my code regarding websocket:

url_websocket = 'wss://advanced-trade-ws.coinbase.com'
now = int(time.time()) # line just added here for reference as it is at the beginning of the code
channel_name = 'level2'
product_ids = 'ETH-USDT', 'ETH-EUR'
str_to_sign_websocket = str(now) + channel_name + ','.join(product_ids)
print(str_to_sign_websocket)
signature_websocket = hmac.new(str_to_sign_websocket.encode('utf-8'), api_secret.encode('utf-8'), hashlib.sha256).hexdigest()
print(signature_websocket)
message = {
  "type": "subscribe",
  "channel": channel_name,
  "api_key": api_key,
  "product_ids": product_ids,
  "signature": signature_websocket,
  "timestamp": str(now)
}

async def main():
    ws = await websockets.connect(url_websocket)
    await ws.send(json.dumps(message))

    async def receive_data():
        while True:
            response = await ws.recv()
            data = json.loads(response)
            print(data)

    while True:
        await receive_data()


if __name__ == '__main__':
    asyncio.run(main())

As far as Coinbase documentation is concerned it looks like the signature generation is correct (hashed using secret key sha256 string using timestamp, channel name and product_ids - concatenated and comma separeted) and then sending subscribe message (type, channel, api_key, product_ids, signature and timestamp). Somehow I am unable to get rid of this authentication failure error…does someone know how to correct my code or if there are any mistakes? Thanks

Hi @wolf2023! Welcome to the forum. We see that you’re having troubles with authenticating through the websocket feed of Advanced trade API, but then we would like to ask the following:

  • Have you tried creating a new API key, and testing your code afterwards?
  • What programming language are you using?

Once we have this information, we will check on this for you with our team to see how we can best assist. We appreciate your patience and understanding.

1 Like

Hi @uncle_genie . Yes I did create a new API key but the result is the same.
I’m using Python.

message = {
  "product_ids": product_ids,
}

Is your json message correct? Does Python automatically produce this:

"products_ids": ["ETH-USDT", "ETH-EUR"],

Should not it be something like this:

message = {
  "product_ids": "[\"" + '","'.join(product_ids) + "\"]",
}
1 Like

Well I have a variable products_ids = ‘ETH-USDT’, ‘ETH-EUR’ that is just being referenced inside a message.
In case you’re talking about the signature then my prehash string variable contains:

str_to_sign_websocket = str(now) + channel_name + ‘,’.join(product_ids)

and that’s how the entire generated prehash string looks like:
1673371057level2ETH-USDT,ETH-EUR #again compliant with the documentation

But does it produce valid json message? Post generated message, don’t forget to remove your api_key before posting.

1 Like

that’s the message:
{“type”: “subscribe”, “channel”: “level2”, “api_key”: “deleted”, “product_ids”: [“ETH-USDT”, “ETH-EUR”], “signature”: “6b17a88c51ae937ccb3d3ced9edd8ea4b41e0e932a9440b4dbe2e2304126efdb”, “timestamp”: “1673373784”}

Looks correct, are you sure you have correct api_key and api_secret? If you can provide minimal python code I will test it with my api key.

1 Like

here’s the code (with deleted keys):

import requests
import base64
import hmac
import hashlib
import time
import json
import uuid
import decimal
import websockets
import asyncio


api_key = ""
api_secret = ""


now = int(time.time())

# Get account info
url_accounts1 = 'https://coinbase.com/api/v3/brokerage/accounts'
str_to_sign_accounts1 = str(now) + 'GET' + '/api/v3/brokerage/accounts' + ''
signature_accounts1 = hmac.new(api_secret.encode('utf-8'), str_to_sign_accounts1.encode('utf-8'), hashlib.sha256).hexdigest()

headers_accounts1 = {
    "CB-ACCESS-SIGN": signature_accounts1,
    "CB-ACCESS-TIMESTAMP": str(now),
    "CB-ACCESS-KEY": api_key,


}
response_accounts1 = requests.request('get', url_accounts1, headers=headers_accounts1)
print(response_accounts1.status_code)
print(response_accounts1.json())


# Get account balance of BTC
btc_balance1 = 0
for account1 in response_accounts1.json()['accounts']:
    if account1['currency'] == 'BTC':
        btc_balance1 = account1['available_balance']['value']
print(btc_balance1)


# Get account balance of ETH
eth_balance1 = 0
for account1 in response_accounts1.json()['accounts']:
    if account1['currency'] == 'ETH':
        eth_balance1 = account1['available_balance']['value']
print(eth_balance1)


# Get account balance of USDT
usdt_balance1 = 0
for account1 in response_accounts1.json()['accounts']:
    if account1['currency'] == 'USDT':
        usdt_balance1 = account1['available_balance']['value']
print(usdt_balance1)


# subscribe to and get websocket feed

url_websocket = 'wss://advanced-trade-ws.coinbase.com'
channel_name = 'level2'
product_ids = 'ETH-USDT', 'ETH-EUR'
str_to_sign_websocket = str(now) + channel_name + ','.join(product_ids)
print(str_to_sign_websocket)
signature_websocket = hmac.new(str_to_sign_websocket.encode('utf-8'), api_secret.encode('utf-8'), hashlib.sha256).hexdigest()
print(signature_websocket)
message = {
  "type": "subscribe",
  "channel": channel_name,
  "api_key": api_key,
  "product_ids": product_ids,
  "signature": signature_websocket,
  "timestamp": str(now)
}

async def main():
    ws = await websockets.connect(url_websocket)
    await ws.send(json.dumps(message))
    print(json.dumps(message))
    async def receive_data():
        while True:
            response = await ws.recv()
            data = json.loads(response)
            print(data)

    while True:
        await receive_data()


if __name__ == '__main__':
    asyncio.run(main())

Your hmac.new line is wrong! First parameter should be secret.

1 Like

Thank you @muktupavels . It works, I don’t know how I could’ve missed that :person_facepalming:
Again, thank you for your time :smiley: