1

I am having trouble signing the message for GDAX API. GDAX API documentation states that status 400 ~ "Bad Request – Invalid request format". Can you please tell me what I need to change?

Thanks!


protected Void doInBackground(String... params) {

        try {
            URL url = new URL(baseUrl+params[0]);

            // Create the urlConnection
            HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();


            urlConnection.setDoInput(true);
            urlConnection.setDoOutput(true);

            urlConnection.setRequestProperty("Content-Type", "application/json");
            urlConnection.setRequestProperty("CB-ACCESS-KEY", key);
            urlConnection.setRequestProperty("CB-ACCESS-SIGN", generate(params[0], "GET", "", String
                    .valueOf(System.currentTimeMillis())));
            String timestamp = String.valueOf(System.currentTimeMillis());
            urlConnection.setRequestProperty("CB-ACCESS-TIMESTAMP", timestamp);
            urlConnection.setRequestProperty("CB-ACCESS-PASSPHRASE", passphrase);

            urlConnection.setRequestMethod("GET");

            int statusCode = urlConnection.getResponseCode();

            if (statusCode ==  200) {
                InputStream inputStream = new BufferedInputStream(urlConnection.getInputStream());

                String response = convertInputStreamToString(inputStream);
                Log.d("TAG", String.valueOf(response));
               } else {
                Log.d("TAG", String.valueOf(statusCode));
            }

        } catch (Exception e) {
            Log.d("TAG", e.getLocalizedMessage());
        }
        return null;
    }

generates CB-ACCESS-SIGN

public String generate(String requestPath, String method, String body, String timestamp) {
    try {
        String prehash = timestamp + method.toUpperCase() + requestPath + body;
        byte[] secretDecoded = Base64.decode(secretKey, Base64.DEFAULT);

        SecretKeySpec keyspec = new SecretKeySpec(secretDecoded, "HmacSHA256");
        Mac sha256 = GDAXConstants.SHARED_MAC;
        sha256.init(keyspec);
        String shadone = Base64.encodeToString(sha256.doFinal(prehash.getBytes()),Base64.DEFAULT);
        return shadone;
    } catch (InvalidKeyException e) {
        e.printStackTrace();
        throw new RuntimeException(new Error("Cannot set up authentication headers."));
    }
}
someone
  • 427
  • 2
  • 11

2 Answers2

2

I was having the same issue for c# code. The problem was that I haven't added the User Agent header. When I did, everything works perfect. My working code is:

HttpClient gdaxClient = new HttpClient();
gdaxClient.DefaultRequestHeaders.Add("User-Agent", ".NET Framework Test Client");

The same for your java code will be:

urlConnection.setRequestProperty("User-Agent", "Java Test Client");
0

Try the code below which I have checked works for someone else. Usually the error is down to "bad request" - not very helpful on its own. However this code will also generate an equivalent curl request which will show you the actual feedback from the server if you copy/paste it on your command prompt. This will typically provide much more informative feedback to help diagnose why your request failed.

Ensure your time is set correctly as the requests are time sensitive. Your API key will also need to be correct/valid for the requests you are making.

Imports of Account object is from the gdax-java library

import com.coinbase.exchange.api.accounts.Account;
import com.google.gson.Gson;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.time.Instant;
import java.util.Arrays;
import java.util.Base64;

public class Testing {

    private final String publicKey;
    private final String passphrase;
    private final String baseUrl;
    private final String secret;

    public Testing(String publicKey,
                   String passphrase,
                   String secret,
                   String baseUrl)
            throws IOException, NoSuchAlgorithmException, InvalidKeyException {
        this.publicKey = publicKey;
        this.passphrase = passphrase;
        this.baseUrl = baseUrl;
        this.secret = secret;
    }

    private Account[] getAccounts() throws IOException, InvalidKeyException, NoSuchAlgorithmException {
        String timestamp = Instant.now().getEpochSecond() + "";
        String path = "/accounts";
        URL url = new URL(baseUrl + path);

        HttpURLConnection con = (HttpURLConnection) url.openConnection();

        con.setRequestProperty("CB-ACCESS-KEY", publicKey);
        con.setRequestProperty("CB-ACCESS-SIGN", signMessage(timestamp, "GET", path));
        con.setRequestProperty("CB-ACCESS-TIMESTAMP", timestamp);
        con.setRequestProperty("CB-ACCESS-PASSPHRASE", passphrase);
        con.setRequestProperty("content-type", "application/json");

        System.out.println("curl -H \"CB-ACCESS-KEY: " + publicKey+ "\" "
                + "-H \"CB-ACCESS-SIGN: " + signMessage(timestamp,"GET", path) + "\" "
                + "-H \"CB-ACCESS-TIMESTAMP: " + timestamp + "\" "
                + "-H \"CB-ACCESS-PASSPHRASE: " + passphrase + "\" " + baseUrl + path);

        con.setConnectTimeout(5000);
        con.setReadTimeout(5000);

        String status = con.getResponseMessage();
        if (status.equals("OK")) {

            BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
            String inputLine;
            StringBuffer content = new StringBuffer();
            while ((inputLine = in.readLine()) != null) {
                content.append(inputLine);
            }
            in.close();
            con.disconnect();

            Gson gson = new Gson();
            Account[] accounts = gson.fromJson(content.toString(), Account[].class);
            Arrays.stream(accounts).forEach(a -> {

                System.out.println("Account: " + a.getCurrency() + ", "
                        + "Balance: " + a.getBalance().toPlainString() + ", "
                        + "Available balance: " + a.getAvailable().toPlainString() + ", "
                        + "Held: " + a.getHold().toPlainString());
            });
            return accounts;
        } else {
            throw new RuntimeException("Something went wrong. Response from server: " + status);
        }
    }

    private String signMessage(String timestamp, String method, String path) throws NoSuchAlgorithmException, InvalidKeyException {
        String prehash = timestamp + method + path;

        Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
        byte[] secretDecoded = Base64.getDecoder().decode(secret);
        SecretKeySpec secret_key = new SecretKeySpec(secretDecoded, "HmacSHA256");
        sha256_HMAC.init(secret_key);

        return Base64.getEncoder().encodeToString(sha256_HMAC.doFinal(prehash.getBytes()));
    }

    public static void main(String[] args) {
        Testing t = null;
        try {
            t = new Testing("publicKey",
                    "passPhrase",
                    "secret",
                    "https://api.gdax.com");
            t.getAccounts();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        }
    }
}
Rob Evans
  • 2,822
  • 1
  • 9
  • 15