43

What is the best way to use preemptive basic http authentication using HttpUrlConnection. (Assume for now I can't use HttpClient).

EDIT for clarification: I'm setting the un/pw correctly in the request header using Base64 encoding. Are there any additional flags or properties that need to be set, or is the fact that I'm setting the basic auth headers for the request all that is needed for preemptive basic auth?

Dave Sims
  • 5,060
  • 3
  • 24
  • 26

6 Answers6

118

If you are using Java 8 or later, java.util.Base64 is usable:

HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
String encoded = Base64.getEncoder().encodeToString((username+":"+password).getBytes(StandardCharsets.UTF_8));  //Java 8
connection.setRequestProperty("Authorization", "Basic "+encoded);


Then use the connection as normal.

If you're using Java 7 or lower, you'll need a method to encode a String to Base64, such as:

byte[] message = (username+":"+password).getBytes("UTF-8");
String encoded = javax.xml.bind.DatatypeConverter.printBase64Binary(message);

Yes, that's all you have to do in order to use Basic Auth. The code above to set the Request Property should be done immediately after opening the connection and before getting the Input or Output streams.

dontocsata
  • 3,021
  • 3
  • 20
  • 19
  • Yes, that's all you have to do. – dontocsata Aug 11 '11 at 16:06
  • Cool, thanks. It turns out my problems were elsewhere. I knew there was a setPreemptiveAuth type interface for HttpClient, wondered if there was something similar for HttpUrlConnection. – Dave Sims Aug 11 '11 at 17:46
  • 37
    Just a little WARNING for anyone who uses android.util.Base64 to do the encoding for this the DEFAULT flag will append a newline char and thus create invalid HTTP requests for you, causing you to waste hours of your time trying to figure out why HTTP servers like nginx report HTTP 400 error codes for your requests! So make sure you use the NO_WRAP flag instead! – Maks Apr 02 '12 at 02:27
  • 10
    The above code didn't work for me. This worked: `String encoded = Base64.encodeToString((username + ":" + password).getBytes("UTF-8"), Base64.NO_WRAP); connection.setRequestProperty("Authorization", "Basic " + encoded);` Note that I hadn't success with `Base64.encode` only (i.e. without 'encodeToString') as it produced some weird result bytes whose ASCII representation didn't even resemble Base64. – ComFreek Mar 07 '15 at 22:20
  • Note for users of java.util.Base64 version: `String encoded = Base64.getEncoder().withoutPadding().encodeToString((username + ":" + password).getBytes(StandardCharsets.UTF_8));` (.withoutPadding() removes extra newline at the end.) – Dalibor Filus Jun 11 '19 at 13:02
3

Incidentally, in case someone else runs into the same, the android problem, is also present if you use org.apache.commons.codec.binary.Base64 and do Base64.encodeBase64String(). You need to do Base64.encodeBase64() and get a byte[] then construct the string.

It caught me offguard entirely that the results would be different for the line ending between those two methods.

Mickäel A.
  • 9,012
  • 5
  • 54
  • 71
dawson
  • 43
  • 3
3

You can use java.net.Authenticator to configure basic auth. globally for every request send by your application, see :

avianey
  • 5,545
  • 3
  • 37
  • 60
3

you need to do this just copy paste it be happy

    HttpURLConnection urlConnection;
    String url;
 //   String data = json;
    String result = null;
    try {
        String username ="danish.hussain@gmail.com";
        String password = "12345678";

        String auth =new String(username + ":" + password);
        byte[] data1 = auth.getBytes(UTF_8);
        String base64 = Base64.encodeToString(data1, Base64.NO_WRAP);
        //Connect
        urlConnection = (HttpURLConnection) ((new URL(urlBasePath).openConnection()));
        urlConnection.setDoOutput(true);
        urlConnection.setRequestProperty("Content-Type", "application/json");
        urlConnection.setRequestProperty("Authorization", "Basic "+base64);
        urlConnection.setRequestProperty("Accept", "application/json");
        urlConnection.setRequestMethod("POST");
        urlConnection.setConnectTimeout(10000);
        urlConnection.connect();
        JSONObject obj = new JSONObject();

        obj.put("MobileNumber", "+97333746934");
        obj.put("EmailAddress", "danish.hussain@dhl.com");
        obj.put("FirstName", "Danish");
        obj.put("LastName", "Hussain");
        obj.put("Country", "BH");
        obj.put("Language", "EN");
        String data = obj.toString();
        //Write
        OutputStream outputStream = urlConnection.getOutputStream();
        BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputStream, "UTF-8"));
        writer.write(data);
        writer.close();
        outputStream.close();
        int responseCode=urlConnection.getResponseCode();
        if (responseCode == HttpsURLConnection.HTTP_OK) {
            //Read
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream(), "UTF-8"));

        String line = null;
        StringBuilder sb = new StringBuilder();

        while ((line = bufferedReader.readLine()) != null) {
            sb.append(line);
        }

        bufferedReader.close();
        result = sb.toString();

        }else {
        //    return new String("false : "+responseCode);
        new String("false : "+responseCode);
        }

    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    } catch (JSONException e) {
        e.printStackTrace();
    }
Syed Danish Haider
  • 1,334
  • 11
  • 15
1

I was having this problem too. And Now I have solved this problem. My code is :

    URL url = new URL(stringUrl);

    String authStr = "MyAPIKey"+":"+"Password";
    System.out.println("Original String is " + authStr);

 // encode data on your side using BASE64
    byte[] bytesEncoded = Base64.encodeBase64(authStr .getBytes());
    String authEncoded = new String(bytesEncoded);

    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
    connection.setRequestProperty("Authorization", "Basic "+authEncoded);

It may help many others. Best of luck.

Khawaja M. Awais
  • 183
  • 1
  • 1
  • 5
-1

Regarding the Base64 encoding problem, I found this library: http://sourceforge.net/projects/migbase64/

I have not fully vetted it but I am using it for the Basic Authentication solution shown above (as well as for image encoding/decoding), and it works well. It provides a parameter for whether or not to include the newline.

djilk
  • 387
  • 3
  • 4