How to sign a Binance HTTP request using Dart

1,687

Your API requires that the signature be presented in hex - hence the regular expression '^[A-Fa-f0-9]{64}$' - i.e. 64 hex upper or lower case characters.

Instead of base64.encode(digest.bytes), which converts the bytes to base 64, convert the bytes to hex using the convert package. NOTE: this is not the dart:convert library. It's a pub package, so you have to add it to pubspec.yaml and import it.

Then you can use hex.encode(digest.bytes).

Share:
1,687
RazerBoy
Author by

RazerBoy

Updated on December 10, 2022

Comments

  • RazerBoy
    RazerBoy over 1 year

    When I try to make a request I get the following error message:

    code: -1100, 
    msg: Illegal characters found in parameter 'signature'; legal range is '^[A-Fa-f0-9]{64}$'
    

    Link to binance API: https://github.com/binance-exchange/binance-official-api-docs/blob/master/rest-api.md

    The request is being made to https://api.binance.com/api/v3/account. The query parameter is only the timestamp, since it's required.

    I'm 100% sure there's something wrong with the way I'm signing the message. I'm sure because it includes characters like '+-/_=', which aren't allowed apparently. The mistake must be somewhere in the middle section of the code, but I can't seem to figure it out.

    I've already looked through the following sites:

    String baseUrl = 'https://api.binance.com/api/v3/account';
    int timeStamp = DateTime.now().millisecondsSinceEpoch;
    String queryParams = 'timestamp=' + timeStamp.toString();
    String secret = 'SECRET_KEY_HERE';
    
    List<int> messageBytes = utf8.encode(queryParams);
    List<int> key = base64.decode(secret);
    Hmac hmac = new Hmac(sha256, key);
    Digest digest = hmac.convert(messageBytes);
    String signature = base64.encode(digest.bytes);
    String url = baseUrl + "?" + "signature=" + signature + "&" + queryParams;
    
    var response = await http.get(
        url,
        headers: {
          "Accept": "application/json",
          "HTTP_ACCEPT_LANGUAGE": "en-US",
          "Accept-Language": "en-US",
          "X-MBX-APIKEY": "API_KEY_HERE"
        }
    );
    
    print(response.body);
    

    EDIT - Working signature

    String baseUrl = 'https://api.binance.com/api/v3/account?';
    int timeStamp = DateTime.now().millisecondsSinceEpoch;
    String queryParams = 'recvWindow=5000' + '&timestamp=' + timeStamp.toString();
    String secret = 'SECRET_KEY_HERE';
    
    List<int> messageBytes = utf8.encode(queryParams);
    List<int> key = utf8.encode(secret);
    Hmac hmac = new Hmac(sha256, key);
    Digest digest = hmac.convert(messageBytes);
    String signature = hex.encode(digest.bytes);
    String url = baseUrl + queryParams + "&signature=" + signature;
    
    var response = await http.get(
      url,
      headers: {
        "Accept": "application/json",
        "HTTP_ACCEPT_LANGUAGE": "en-US",
        "Accept-Language": "en-US",
        "X-MBX-APIKEY": "API_KEY_HERE"
      }
    );
    
    print(response.body);
    
  • RazerBoy
    RazerBoy about 5 years
    Hello and thank you for your reply. I've tried hex.encode(digest.bytes) and I do believe it works. I'm still having problems with code: -1022, msg: Signature for this request is not valid. But when I resolve this I'll mark your answer as the correct one. Since I do believe your answer is correct. Thank you again kind stranger.
  • RazerBoy
    RazerBoy about 5 years
    Yes, it does work. I just had to change String signature = base64.encode(digest.bytes); to String signature = hex.encode(digest.bytes);. But I also had to change List<int> key = base64.decode(secret); to List<int> key = utf8.encode(secret);. Again, thank you for your help! I'll add the working code to my question and mark your answer as the correct one.