Reputation: 116
on Dart i try to reach AUth https. However i got 401 error. I followed every single instructions on api document. Signature is correct, payload is correct.. but i got 401 error.. Could you please help about this issue? Is any body using Dart on Poloniex V2 api before?
Here is the Instruction that i followed
Thanks
import 'dart:convert';
import 'package:crypto/crypto.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
const String poloniexPrivateApiKey = "xxxxxxxxxx";
const String poloniexPrivateSecretKey = "xxxxxxxx";
const String url = "https://api.poloniex.com";
const String publicApiUrl = "https://poloniex.com/public";
class PoloniexApiClient {
static String v2Accounts = "/accounts";
static String v2Orders = "/orders";
static String v2Markets = "/markets";
String apiKey;
String secretKey;
String host;
PoloniexApiClient({this.apiKey = poloniexPrivateApiKey, this.secretKey = poloniexPrivateSecretKey, this.host = url});
Future accounts() async {
try {
Map<String, dynamic> map = {};
var response = await PoloniexSignatureHelper.generateResponse(apiKey, secretKey, host, v2Accounts, map);
debugPrint("accountResponse: ${response.toString()}");
} catch (e) {
debugPrint(e.toString());
}
}
}
class PoloniexSignatureHelper {
static String contentType = "Content-Type";
static String jsonType = "application/json";
static String requestMethodGet = "GET";
static String requestMethodPost = "POST";
static String requestMethodDelete = "DELETE";
static String headerTimeStamp = "signTimestamp";
static String headerKey = "key";
static String headerSignMethod = "signatureMethod";
static String headerSignVersion = "signatureVersion";
static String headerSignature = "signature";
static String signatureMethodValue = "HmacSHA256";
static String signatureVersionValue = "2";
static Future<String> generateResponse(String apiKey, secretKey, host, path, Map<String, dynamic> paramMap) async {
String timestamp = DateTime.now().millisecondsSinceEpoch.toString();
String payload = generateSignatureRequestString(requestMethodGet, path, timestamp, paramMap);
print(payload);
String signature = generateSignature(secretKey, payload);
print(signature);
String response = await executeRequest(host, path, apiKey, timestamp, signature, paramMap);
print(response);
return response;
}
static String generateSignatureRequestString(String method, path, timestamp, Map<String, dynamic> paramMap) {
var sortedParamMap = sortMapASCII(paramMap, timestamp);
var encoded;
if (method == requestMethodGet) {
encoded = sortedParamMap.keys
.map((key) => "${Uri.encodeComponent(key)}=${Uri.encodeComponent(paramMap[key].toString())}")
.join("&");
} else {
sortedParamMap.remove(headerTimeStamp);
var requestBody = jsonEncode(sortedParamMap);
encoded = "requestBody=$requestBody&signTimestamp=$timestamp";
}
var requestString = method + "\n" + path + "\n" + encoded;
return requestString;
}
static String generateSignature(String secretKey, String requestString) {
final keyBytes = base64Decode(secretKey);
final dataBytes = utf8.encode(requestString);
final hMacBytes = Hmac(sha256, keyBytes).convert(dataBytes).bytes;
final hMacBase64 = base64Encode(hMacBytes);
var sign = hMacBase64;
return sign;
}
static Future<String> executeRequest(
String host, path, apiKey, timestamp, signature, Map<String, dynamic> paramMap) async {
String url = host + path;
if (paramMap.isNotEmpty && paramMap.length > 0) {
var queryStringBuffer = "?";
paramMap.forEach((key, value) {
queryStringBuffer = queryStringBuffer + key + "=" + value.toString() + "&";
});
String queryString = queryStringBuffer.substring(0, queryStringBuffer.length - 1);
url = url + queryString;
}
print(url);
Map<String, String> _headers = {
// contentType: jsonType,
// contentType: "application/x-www-form-urlencoded",
headerKey: apiKey,
headerSignMethod: signatureMethodValue,
headerSignVersion: signatureVersionValue,
headerTimeStamp: timestamp,
headerSignature: signature
};
var result;
try {
var response = await http.get(Uri.parse(url), headers: _headers);
// if (response.statusCode == 200) {
// String data = response.body;
// result = data;
// }
result = response.statusCode.toString(); // return 401??
} catch (e) {
result = e.toString();
}
return result;
}
static Map<String, dynamic> sortMapASCII(Map<String, dynamic> paramMap, timestamp) {
paramMap.addAll({headerTimeStamp: timestamp});
var paramKeys = paramMap.keys.map((key) => "$key").toList();
paramKeys.sort(((a, b) => a.compareTo(b)));
Map<String, dynamic> sortedParamMap = {};
paramKeys.forEach((key) => sortedParamMap.addAll({"$key": "${paramMap[key]}"}));
print(sortedParamMap);
return sortedParamMap;
}
}
Upvotes: 3
Views: 379
Reputation: 176
In case anyone has problems with PHP and 401 error, You should remember to output the data as raw binary data before encoding to base64 by switching $binary
bool
to true
inside hash_hmac
function. I spent hours on this until I found the problem. I hope this answer helps.
Here's how :
<?php
base64_encode(hash_hmac('sha256',$request_string,$secret,true)) // *true is important
?>
To this day, 11.25.2023, there is no mention in the Poloneix docs about outputting the data as raw binary data when hashing the data. I hope they add the description.
Upvotes: 3