0

I'm trying to use HttpUrlConnection to send a POST. Everything seems fine but it keeps returns 400, as if the parameters are not sent in the DataOutputStream, or anyway sent in a malformed way.

public String doDBAuth(String dbURL, String dbUser, String dbPassword) throws IOException {
    HttpURLConnection connection = null;

    String res = null;

    try {
        BufferedReader reader;
        StringBuffer buffer;

        URL url = new URL(dbURL + "/auth");
        connection = (HttpURLConnection) url.openConnection();          
        String urlParameters  = "username=actn-admin&password=Test@&cliend_id=admin-cli&grant_type=password";
        byte[] postData = urlParameters.getBytes(StandardCharsets.UTF_8 );
        int postDataLength = postData.length;



        connection.setRequestMethod("POST");
        connection.setReadTimeout(40000);
        connection.setConnectTimeout(40000);
        connection.setDoOutput(true);   
        connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");     
        connection.setRequestProperty("Content-Length", Integer.toString(postDataLength));
        connection.setDoInput(true);


        try (DataOutputStream wr = new DataOutputStream(connection.getOutputStream())) {
            wr.writeBytes(urlParameters);
            wr.flush();
        }


        int responseCode = connection.getResponseCode();

        int status = connection.getResponseCode();
        InputStream inputStream;
        if (status == HttpURLConnection.HTTP_OK) {
            inputStream = connection.getInputStream();
        } else {
            inputStream = connection.getErrorStream();
        }
        reader = new BufferedReader(new InputStreamReader(inputStream));
        buffer = new StringBuffer();
        String line = "";
        while ((line = reader.readLine()) != null) {
            buffer.append(line);
        }
        res = buffer.toString();

    } catch (MalformedURLException e) {
        e.printStackTrace();
    } catch (ProtocolException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }   
    return res;
}  

This is what is returned:

{"error":"unauthorized_client","error_description":"INVALID_CREDENTIALS: Invalid client credentials"}

This is weird cause this curl works properly:

curl --location --request POST '<URL>/auth' \
> --header 'Content-Type: application/x-www-form-urlencoded' \
> --data-urlencode 'username=actn-admin' \
> --data-urlencode 'password=Test@' \
> --data-urlencode 'client_id=admin-cli' \
> --data-urlencode 'grant_type=password' -k

and it returns me the access token I'm expecting

LucaP
  • 638
  • 1
  • 12
  • 34

1 Answers1

1

Keys and values need to be URL encoded (here's the spec). Replacing "Test@" with "Test%40" should be enough in your example. For a future-proof solution you should encode all keys and values (e.g. with URLEncoder)

rmunge
  • 3,653
  • 5
  • 19
  • I added `String stringToReverse = URLEncoder.encode(urlParameters, "UTF-8");` but it didn't solve. Now I have this error: `{"error":"invalid_request","error_description":"Missing form parameter: grant_type"}` I suppose now the error is in the Content-Type, how should I calculate it, using the parameters or the encoded ones? From postman if I don't set the Content-Type it returns the same error of invalid grant type – LucaP Jul 09 '21 at 11:13
  • @LucaP please note that you will get a 400 again if your username / password should contain any non-ASCII character in future. To avoid this, please write the postData array directly to the output stream instead of using writeBytes, which does not work correctly with non-ASCII characters. – rmunge Jul 09 '21 at 11:20
  • 1
    @LucaP you must not encode the = characters, only the keys and the values – rmunge Jul 09 '21 at 11:22
  • see the second example in this answer: https://stackoverflow.com/a/40576153/13510562 – rmunge Jul 09 '21 at 11:24
  • You are right, I was encoding the whole body. Fixed now and it's working. – LucaP Jul 09 '21 at 12:31