BTCMarkets / API

API
119 stars 30 forks source link

Authentication Issue with Swift (/account/balance) #123

Closed Ad0be closed 4 years ago

Ad0be commented 6 years ago

Hi,

I'm trying to authenticate an /account/balance api request in swift but get:

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

I have made non authenticated api requests without a problem but have not been able to get this call or the sample /order/history to work. Im using account balance as a test to try and keep it simple without httpbody etc. I would appreciate any suggestions anyone could provide.

Code Snippet is below:

    func getBtcmAccountBalance()
    {
        let timeinterval = (Date.timeIntervalBetween1970AndReferenceDate + Date.timeIntervalSinceReferenceDate) * 1000

        let timeintervalString = String(format: "%.0f", timeinterval)
        print("Time Interval: " + timeintervalString)

        let apikey = publickey_btcm
        let stringToSign = "/account/balance" + "\n" + timeintervalString + "\n"
        let resultingSignature = hmac(hashName:"SHA512", message:stringToSign, key:privatekey_btcm)
        print("sig: " + resultingSignature!.base64EncodedString())

        let jsonUrlString = "https://api.btcmarkets.net/account/balance"
        let url = URL(string: jsonUrlString)!
        let session = URLSession.shared

        let request = MutableURLRequest(url: url)
        request.httpMethod = "GET"
        request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
        request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Accept")
        request.setValue(apikey, forHTTPHeaderField: "apikey")
        request.setValue(timeintervalString, forHTTPHeaderField: "timestamp")
        request.setValue(resultingSignature?.base64EncodedString(), forHTTPHeaderField: "signature")

        print(request.allHTTPHeaderFields)

        session.dataTask(with: request as URLRequest) { (data, response, err) in

            guard let data = data else {
                print("Error Getting Data")
                return
            }

            let dataAsString = String(data: data, encoding: .utf8)
            print("Webisite Response: " + dataAsString!)
            }.resume()

    }

HTTP request outputted and debugged through Charles is:

:method | GET
-- | --
:scheme | https
:path | /account/balance
:authority | api.btcmarkets.net
cookie | __cfduid=daa1e73a8c3e3d074fd322f612cc8496c1518222685
accept | application/json; charset=utf-8
content-type | application/json; charset=utf-8
apikey | c21a33c4-06bf-4bd9-b8aa-d9c98ef3f6be
user-agent | trader/1 CFNetwork/889.9 Darwin/17.2.0 (x86_64)
signature | 4QfJay6gAXOqpP14ALsyy6r6BMb0LhS/MGSnLpFhzHs/QyofPGo8w8rxRuhmCh2vtV/kAI5S3ccai2j6dSmlAg==
accept-language | en-au
timestamp | 1519696426317
accept-encoding | br, gzip, deflate

Points to Note:

justin-ngin commented 6 years ago

Hi @Ad0be ,

Yes, the private key does need to be decoded from base64 before being used in the signature. In my experience, this produces output that looks different depending on how you are trying to print it. I will add a sample authentication signature for the /account/balance endpoint as this is usually the first place people start with designing and debugging. As long as you can replicate the signature that will soon be there, you will be using your private key correctly.

Regards, Justin

Ad0be commented 6 years ago

Thanks Justin.

Still having trouble getting this to work in swift but thanks for the examples. I think it will help people a lot. Cheers, Kane.

martin-nginio commented 4 years ago

Hi @Ad0be

Thank you for your feedback.

Please find below our a sample client application using SWIFT language: https://github.com/BTCMarkets/api-v3-client-swift

This sample was written for our new API version but it can also be used (with minor update) for previous versions as well: https://api.btcmarkets.net/doc/v3#section/Introduction

Regards, Martin

martin-nginio commented 4 years ago

closing the issue.