BTCMarkets / API

API
119 stars 30 forks source link

Authentication error - {'success': False, 'errorCode': 1, 'errorMessage': 'Authentication failed.'} #128

Closed Tallthunder closed 4 years ago

Tallthunder commented 6 years ago

Keep getting the above code. Not sure why. I would appreciate any help.

Here is the code I am using ( Its not my public/private API keys as I have checked them multiple times ):

import base64, hashlib, hmac, time, urllib, urllib.request, json from collections import OrderedDict

base_url = 'https://api.btcmarkets.net'

def request(action, key, signature, timestamp, path, data):

header = {
    'Accept': 'application/json', 
    'Accept-Charset': 'UTF-8',  
    'Content-Type': 'application/json',
    'apikey': key,
    'timestamp': timestamp,
    'signature': signature,
}

request = urllib.request.Request(base_url + path, data, header)
if action == 'post':
    response = urllib.request.urlopen(request, data)
else:
    response = urllib.request.urlopen(request)
return json.loads(response.read())

def get_request(key, secret, path):

nowInMilisecond = str(int(time.time() * 1000))
stringToSign = path + "\n" + nowInMilisecond + "\n"  

presignature = base64.b64encode(hmac.new(secret, stringToSign.encode('utf-8'), digestmod=hashlib.sha512).digest())
signature = presignature.decode('utf8')

return request('get', key, signature, nowInMilisecond, path, None)    

def post_request(key, secret, path, postData):

nowInMilisecond = str(int(time.time() * 1000))
stringToSign = path + "\n" + nowInMilisecond + "\n" + postData  

signature = base64.b64encode(hmac.new(secret, stringToSign.encode('utf-8'), digestmod=hashlib.sha512).digest())

return request('post', key, signature, nowInMilisecond, path, postData) 

class BTCMarkets:

def __init__(self, key, secret):
    self.key = key
    self.secret = base64.b64decode(secret)

def account_balance(self):

    return get_request(self.key, self.secret, '/account/balance') 

api_key = 'xxxxxx' private_key = 'xxxxx'

client = BTCMarkets (api_key, private_key)

print (client.get_market_tick('ETH','AUD'))

print (client.account_balance())

Tallthunder commented 6 years ago

@justin-ngin @martin-nginio I have gone through the entire issues folder, but not able to find a good answer. I have base64 decoded my key, base64 encoded the HMAC signature, made sure the headers are in the right order, time stamp is in the correct format. My only guess is either

Thanks again!

justin-ngin commented 6 years ago

Hi @Tallthunder ,

I couldn't replicate the issue with your above code, because the interpreter didn't like it. Once I tweaked it to the below, account balance is working correctly for me. Please let me know if you are able to use this as well.

import base64, hashlib, hmac, time, urllib2, urllib2, json
from collections import OrderedDict

base_url = 'https://api.btcmarkets.net'

def request(action, key, signature, timestamp, path, data):

    header = {
        'Accept': 'application/json', 
        'Accept-Charset': 'UTF-8',  
        'Content-Type': 'application/json',
        'apikey': key,
        'timestamp': timestamp,
        'signature': signature,
    }

    http_request = urllib2.Request(base_url + path, data, header)
    if action == 'post':
        response = urllib2.urlopen(http_request, data)
    else:
        response = urllib2.urlopen(http_request)
    return json.loads(response.read())

def get_request(key, secret, path):

    nowInMilisecond = str(int(time.time() * 1000))
    stringToSign = path + "\n" + nowInMilisecond + "\n"  

    presignature = base64.b64encode(hmac.new(secret, stringToSign.encode('utf-8'), digestmod=hashlib.sha512).digest())
    signature = presignature.decode('utf8')

    return request('get', key, signature, nowInMilisecond, path, None)    

def post_request(key, secret, path, postData):

    nowInMilisecond = str(int(time.time() * 1000))
    stringToSign = path + "\n" + nowInMilisecond + "\n" + postData  

    signature = base64.b64encode(hmac.new(secret, stringToSign.encode('utf-8'), digestmod=hashlib.sha512).digest())

    return request('post', key, signature, nowInMilisecond, path, postData) 

class BTCMarkets:

    def __init__(self, key, secret):
        self.key = key
        self.secret = base64.b64decode(secret)

    def account_balance(self):

        return get_request(self.key, self.secret, '/account/balance') 

api_key = 'xxxx'
private_key = 'yyyy'

client = BTCMarkets (api_key, private_key)

print (client.account_balance())

Cheers, Justin

Tallthunder commented 6 years ago

Hi @justin-ngin , Thanks for getting back to me. I tried the above code in jupyter notebook with python 3 after converting urllib2-> urllib.request as I had it on the first post and I am still getting the same error. This makes me think it is either something to do with python 3's urllib.request module or just the interpreter that I am using(since you seem to have issues with yours).

Which interpreter are you using?

I will try the above code with python 2 and get back to you.

Kind regards,

Jim

Tallthunder commented 6 years ago

Just switched to python2 and used the native python interpreter. Literally copied and pasted what you posted and still getting the same error-

{u'errorCode': 1, u'errorMessage': u'Authentication failed.', u'success': False}

I wonder, what it could be...

justin-ngin commented 6 years ago

I'm using Python 2.7 as my interpreter for the code I provided.

If you're using the code above, and you're sure that your keys are correct, the other most likely thing is your timestamp variance is too high. Please check that your machine is connected to a time server, and if you have the option, force it to sync, and try again.

I will whip out my jupyter notebook and try running it through that as well.

Tallthunder commented 6 years ago

Hey @justin-ngin

I have checked my keys multiple times and I am pretty sure it is accurate .

I checked via command prompt and seems like my PC is synced to the NTP server .

Is there an alternate way to get an appropriate timestamp ? I have used the timestamp from the ticker for other exchanges succesfully but not sure if it would work for BTCmarkets.

justin-ngin commented 6 years ago

Hi @Tallthunder ,

I have just tested this inside jupyter notebook, and the account balance call is working for me. After further investigation, I don't think the sole cause would be your timestamp, as the API actually returns an error message specifically for timestamps that are out of range. If you haven't already, can you please clone or download this project: BTC-Markets Python and use your API keys in main.py and try using the account balance call?

Cheers, Justin

Tallthunder commented 6 years ago

Hey @justin-ngin ,

Just tried that and am still getting the same error code. The only thing that works for me is get_market_tick.

At this point I have ruled out timestamp, syntax, keys, use of the Request module, python 3, base 64 decoding/ encoding, signature matching (using the sample keys and timestamp provided on btcmarkets api page) and order of headers.

Would it be worth it to try a different operating system?? Btcmarkets is the only exchange I am having trouble with. I used ccxt library for the other exchanges.

justin-ngin commented 6 years ago

Hi @Tallthunder ,

You can replicate the example signatures in the wiki using those timestamps and keys? What operating system are you running, and would you be able to try with a different language?

Regards, Justin

Tallthunder commented 6 years ago

Hey @justin-ngin Yes, I am able to replicate the signatures using the sample timestamp and private key. I am running a windows 7 home premium 64 bit OS. I tried Java but ended up bashing my head in since I had to learn the language from scratch. Ended up crashing my PC and had to reboot. So that is on hold for now.

I have come across a python wrapper searching through the issues tab. I might give that a go.

Tallthunder commented 6 years ago

Hey @justin-ngin

Just tried with a Java wrapper for python and Im getting the same error code- 1, authentication failure. The only possible solution would be an incorrect public and private API key. None of the other variables can possibly be causing the issue. If the issue is my key, how would I go about fixing this?

JuanNavasJN commented 5 years ago

Hi, I have the same problem with PHP - Laravel

This is my function:

private function RequestApi($path, $public, $private){

        $timestamp = time()*1000;

        $message = $path . "\n" . $timestamp . "\n";

        $signature = base64_encode(hash_hmac('sha512', $message, base64_decode($private), true));

        // Create a stream
         $opts = [
            "http" => [
                "method" => "GET",
                "header" => "apikey: $public\r\n". "timestamp: $timestamp\r\n"."signature: $signature\r\n"
            ]
        ];

        $this->context = stream_context_create($opts);

        try{
             // Open the file using the HTTP headers set above
             $request = file_get_contents('https://api.btcmarkets.net'.$path, false, $this->context);
             dd($request);
        }catch(Exception $e){
            dd($e->getMessage());
        }

        return json_decode($request);
    }

This is the response:

"{"success":false,"errorCode":1,"errorMessage":"Authentication failed."}"

Any suggestions?

Regards, Juan

martin-nginio commented 5 years ago

Hi @Tallthunder

A sample client API code (mainly authentication) for Python 3 has been added here: https://github.com/BTCMarkets/api-client-python3

The code has been tested with Python 3.7 (on Ubuntu) but it should be the same on other operating systems.

Thanks for your feedback.

martin-nginio commented 5 years ago

Hi @JuanNavasJN

Please feel free to take a look at the following PHP authentication sample code: https://github.com/BTCMarkets/api-client-php

The code has been tested with PHP 7.1.23 but it should work with higher versions as well.

Thanks for your feedback.

JuanNavasJN commented 5 years ago

Thanks @martin-nginio

I already resolved it. Apparently I had problems with my keys.

martin-nginio commented 4 years ago

closing the issue.