177

I am trying to mimic the functionality of this curl command in Java:

curl --basic --user username:password -d "" http://ipaddress/test/login

I wrote the following using Commons HttpClient 3.0 but somehow ended up getting an 500 Internal Server Error from the server. Can someone tell me if I'm doing anything wrong?

public class HttpBasicAuth {

    private static final String ENCODING = "UTF-8";

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        try {

            HttpClient client = new HttpClient();

            client.getState().setCredentials(
                    new AuthScope("ipaddress", 443, "realm"),
                    new UsernamePasswordCredentials("test1", "test1")
                    );

            PostMethod post = new PostMethod(
                    "http://address/test/login");

            post.setDoAuthentication( true );

            try {
                int status = client.executeMethod( post );
                System.out.println(status + "\n" + post.getResponseBodyAsString());
            } finally {
                // release any connection resources used by the method
                post.releaseConnection();
            }
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
   } 

And I later tried a Commons HttpClient 4.0.1 but still the same error:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;


public class HttpBasicAuth {

    private static final String ENCODING = "UTF-8";

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub

        try {
            DefaultHttpClient httpclient = new DefaultHttpClient();

            httpclient.getCredentialsProvider().setCredentials(
                    new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT), 
                    new UsernamePasswordCredentials("test1", "test1"));

            HttpPost httppost = new HttpPost("http://host:post/test/login");

            System.out.println("executing request " + httppost.getRequestLine());
            HttpResponse response;
            response = httpclient.execute(httppost);
            HttpEntity entity = response.getEntity();

            System.out.println("----------------------------------------");
            System.out.println(response.getStatusLine());
            if (entity != null) {
                System.out.println("Response content length: " + entity.getContentLength());
            }
            if (entity != null) {
                entity.consumeContent();
            }

            httpclient.getConnectionManager().shutdown();  
        } catch (ClientProtocolException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
}
Legend
  • 113,822
  • 119
  • 272
  • 400
  • um, whats the error showing up in the server logs? – hvgotcodes Jul 19 '10 at 17:30
  • Ah... I don't have access to the server logs :( – Legend Jul 19 '10 at 17:36
  • Most of the time the Authorization key we are using could be wrong. Check http://dev.tapjoy.com/faq/how-to-find-sender-id-and-api-key-for-gcm/ to see you are using the correct key or not . I also got confused while selecting API key for firebase We have to use SENDER ID - API KEY pair in Cloud messaging tab under firebase setting. i.e. Go to firebase App--> Go to app setting --> Cloud Messaging there you can find Sender Id <==> API key and this API key you can use to send FCM. – Rahul Feb 14 '17 at 09:01

10 Answers10

225

Have you tried this (using HttpClient version 4):

String encoding = Base64.getEncoder().encodeToString((user + ":" + pwd).getBytes());
HttpPost httpPost = new HttpPost("http://host:post/test/login");
httpPost.setHeader(HttpHeaders.AUTHORIZATION, "Basic " + encoding);

System.out.println("executing request " + httpPost.getRequestLine());
HttpResponse response = httpClient.execute(httpPost);
HttpEntity entity = response.getEntity();
Nicholas DiPiazza
  • 10,029
  • 11
  • 83
  • 152
Buhake Sindi
  • 87,898
  • 29
  • 167
  • 228
  • 79
    Better to use `java.util.Base64` as of Java 8: `Base64.getEncoder().encodeToString(("test1:test1").getBytes());` – Michael Berry Nov 04 '16 at 12:50
  • 1
    I prefer to use javax.xml.bind.DatatypeConverter to convert from to base64, hex and other conversion. it a part of jdk so no need to include any additional JAR. – Mubashar Jan 03 '18 at 04:12
  • 1
    This is the version works for me in my use case where the HttpClient is already provided and you can not set the setDefaultCredentialsProvider() on the builder while build the httpclient. Also I like it because it is per call scope. Not on the whole httpclient scope. – Tony Aug 15 '19 at 16:23
128

Ok so this one works. Just in case anybody wants it, here's the version that works for me :)

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Base64;


public class HttpBasicAuth {

    public static void main(String[] args) {

        try {
            URL url = new URL ("http://ip:port/login");
            String encoding = Base64.getEncoder().encodeToString(("test1:test1").getBytes(‌"UTF‌​-8"​));

            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("POST");
            connection.setDoOutput(true);
            connection.setRequestProperty  ("Authorization", "Basic " + encoding);
            InputStream content = (InputStream)connection.getInputStream();
            BufferedReader in   = 
                new BufferedReader (new InputStreamReader (content));
            String line;
            while ((line = in.readLine()) != null) {
                System.out.println(line);
            }
        } catch(Exception e) {
            e.printStackTrace();
        }

    }

}
The Student
  • 27,520
  • 68
  • 161
  • 264
Legend
  • 113,822
  • 119
  • 272
  • 400
  • 4
    Cannot find `Base64Encoder`. Jonas can you please give the full jar? Also whats the fully qualified class name of `Base64Encoder`? – Jus12 Feb 12 '13 at 12:05
  • @Amitabh: For `Base64Encoder` look [here](http://stackoverflow.com/questions/13109588/base64-encoding-in-java). For `Base64` look in commons-codec-1.6.jar in 4.2.5.zip at [Apache HttpComponents Downloads](http://hc.apache.org/downloads.cgi), [doc](http://commons.apache.org/proper/commons-codec/apidocs/org/apache/commons/codec/binary/Base64.html), `import org.apache.commons.codec.binary.Base64;` – Lernkurve May 15 '13 at 15:49
  • 29
    This does not answer the question. The question asks about using HttpClient and this answer does not use HttpClient. – Paul Croarkin Oct 29 '13 at 12:35
  • Check out the code below. (http://stackoverflow.com/a/24618341/155167) It uses the Base64 class from the Apache Commons and, more importantly, compiles successfully. – Mario Jul 07 '14 at 19:30
  • 9
    If you are using Java 8, you can use java.util.Base64. – WW. Jun 16 '15 at 06:52
  • 4
    Here's the line for java.util.Base64 `String encoding = Base64.getEncoder().encodeToString("test1:test1".getBytes("utf-8"));` – Joe Sep 11 '16 at 01:39
  • For android.util.Base64: `String encoding = new String(Base64.encode((pUsername+":"+pPassword).getBytes("UTF-8"), Base64.DEFAULT));` – Mapsy Apr 26 '17 at 09:21
  • I am getting this error: Exception in thread "main" java.lang.Error: Unresolved compilation problem: Syntax error on token "Invalid Character", delete this token at codegauge.analyzer.HttpBasicAuth.main(HttpBasicAuth.java:17) – Monti Chandra Sep 04 '17 at 05:36
  • I prefer to use javax.xml.bind.DatatypeConverter to convert from to base64, hex and other conversion. it a part of jdk so no need to include any additional JAR. – Mubashar Jan 03 '18 at 04:11
  • For those who can't use Base64, `String encoded = DatatypeConverter.printBase64Binary("yourString".getBytes());` – Alex Feb 11 '20 at 15:52
  • Note that it's possible (and, in fact, cleaner) to replace `getBytes("utf-8")` with `getBytes(StandardCharsets.UTF_8)`. This also removes the need to catch `UnsupportedEncodingException` which can be thrown otherwise (because the method can't know the plain String encoding ID you're passing isn't utter nonsense). – Egor Hans Mar 25 '20 at 15:11
  • Also, `catch (Exception e) { e.printStackTrace() }` is horribly unclean. A better way to handle exceptions is to throw a `RuntimeException` (or even better, a custom `ThisShouldNotHappenException`) with individual message for every exception type and the respective exception attached as cause. – Egor Hans Mar 25 '20 at 15:23
19

This is the code from the accepted answer above, with some changes made regarding the Base64 encoding. The code below compiles.

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;

import org.apache.commons.codec.binary.Base64;


public class HttpBasicAuth {

    public static void main(String[] args) {

        try {
            URL url = new URL ("http://ip:port/login");

            Base64 b = new Base64();
            String encoding = b.encodeAsString(new String("test1:test1").getBytes());

            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("POST");
            connection.setDoOutput(true);
            connection.setRequestProperty  ("Authorization", "Basic " + encoding);
            InputStream content = (InputStream)connection.getInputStream();
            BufferedReader in   = 
                new BufferedReader (new InputStreamReader (content));
            String line;
            while ((line = in.readLine()) != null) {
                System.out.println(line);
            }
        } 
        catch(Exception e) {
            e.printStackTrace();
        }
    }
}
Mario
  • 2,397
  • 2
  • 24
  • 41
14

A small update - hopefully useful for somebody - it works for me in my project:

  • I use the nice Public Domain class Base64.java from Robert Harder (Thanks Robert - Code availble here: Base64 - download and put it in your package).

  • and make a download of a file (image, doc, etc.) with authentication and write to local disk

Example:

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;

public class HttpBasicAuth {

public static void downloadFileWithAuth(String urlStr, String user, String pass, String outFilePath) {
    try {
        // URL url = new URL ("http://ip:port/download_url");
        URL url = new URL(urlStr);
        String authStr = user + ":" + pass;
        String authEncoded = Base64.encodeBytes(authStr.getBytes());

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

        File file = new File(outFilePath);
        InputStream in = (InputStream) connection.getInputStream();
        OutputStream out = new BufferedOutputStream(new FileOutputStream(file));
        for (int b; (b = in.read()) != -1;) {
            out.write(b);
        }
        out.close();
        in.close();
    }
    catch (Exception e) {
        e.printStackTrace();
    }
}
}
7

Here are a few points:

  • You could consider upgrading to HttpClient 4 (generally speaking, if you can, I don't think version 3 is still actively supported).

  • A 500 status code is a server error, so it might be useful to see what the server says (any clue in the response body you're printing?). Although it might be caused by your client, the server shouldn't fail this way (a 4xx error code would be more appropriate if the request is incorrect).

  • I think setDoAuthentication(true) is the default (not sure). What could be useful to try is pre-emptive authentication works better:

    client.getParams().setAuthenticationPreemptive(true);
    

Otherwise, the main difference between curl -d "" and what you're doing in Java is that, in addition to Content-Length: 0, curl also sends Content-Type: application/x-www-form-urlencoded. Note that in terms of design, you should probably send an entity with your POST request anyway.

Bruno
  • 119,590
  • 31
  • 270
  • 376
7

while using Header array

String auth = Base64.getEncoder().encodeToString(("test1:test1").getBytes());
Header[] headers = {
    new BasicHeader(HTTP.CONTENT_TYPE, ContentType.APPLICATION_JSON.toString()),
    new BasicHeader("Authorization", "Basic " +auth)
};
rjdkolb
  • 10,377
  • 11
  • 69
  • 89
manoj
  • 3,391
  • 2
  • 20
  • 30
5

Thanks for all answers above, but for me, I can not find Base64Encoder class, so I sort out my way anyway.

public static void main(String[] args) {
    try {
        DefaultHttpClient Client = new DefaultHttpClient();

        HttpGet httpGet = new HttpGet("https://httpbin.org/basic-auth/user/passwd");
        String encoding = DatatypeConverter.printBase64Binary("user:passwd".getBytes("UTF-8"));
        httpGet.setHeader("Authorization", "Basic " + encoding);

        HttpResponse response = Client.execute(httpGet);

        System.out.println("response = " + response);

        BufferedReader breader = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
        StringBuilder responseString = new StringBuilder();
        String line = "";
        while ((line = breader.readLine()) != null) {
            responseString.append(line);
        }
        breader.close();
        String repsonseStr = responseString.toString();

        System.out.println("repsonseStr = " + repsonseStr);

    } catch (IOException e) {
        e.printStackTrace();
    }

}

One more thing, I also tried

Base64.encodeBase64String("user:passwd".getBytes());

It does NOT work due to it return a string almost same with

DatatypeConverter.printBase64Binary()

but end with "\r\n", then server will return "bad request".

Also following code is working as well, actually I sort out this first, but for some reason, it does NOT work in some cloud environment (sae.sina.com.cn if you want to know, it is a chinese cloud service). so have to use the http header instead of HttpClient credentials.

public static void main(String[] args) {
    try {
        DefaultHttpClient Client = new DefaultHttpClient();
        Client.getCredentialsProvider().setCredentials(
                AuthScope.ANY,
                new UsernamePasswordCredentials("user", "passwd")
        );

        HttpGet httpGet = new HttpGet("https://httpbin.org/basic-auth/user/passwd");
        HttpResponse response = Client.execute(httpGet);

        System.out.println("response = " + response);

        BufferedReader breader = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
        StringBuilder responseString = new StringBuilder();
        String line = "";
        while ((line = breader.readLine()) != null) {
            responseString.append(line);
        }
        breader.close();
        String responseStr = responseString.toString();
        System.out.println("responseStr = " + responseStr);

    } catch (IOException e) {
        e.printStackTrace();
    }
}
chenyi1976
  • 1,104
  • 9
  • 17
  • Base64.encodeBase64String("user:passwd".getBytes()); worked for me. DatatypeConverter.printBase64Binary() also worked for me. It could be that you made a mistake in the message body in earlier case and that caused a bad request. Or maybe it depends on server. – rents Feb 12 '16 at 09:09
5

An easy way to login with a HTTP POST without doing any Base64 specific calls is to use the HTTPClient BasicCredentialsProvider

import java.io.IOException;
import static java.lang.System.out;
import org.apache.http.HttpResponse;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.HttpClientBuilder;

//code
CredentialsProvider provider = new BasicCredentialsProvider();
UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(user, password);
provider.setCredentials(AuthScope.ANY, credentials);
HttpClient client = HttpClientBuilder.create().setDefaultCredentialsProvider(provider).build();

HttpResponse response = client.execute(new HttpPost("http://address/test/login"));//Replace HttpPost with HttpGet if you need to perform a GET to login
int statusCode = response.getStatusLine().getStatusCode();
out.println("Response Code :"+ statusCode);
rjdkolb
  • 10,377
  • 11
  • 69
  • 89
3

HttpBasicAuth works for me with smaller changes

  1. I use maven dependency

    <dependency>
        <groupId>net.iharder</groupId>
        <artifactId>base64</artifactId>
        <version>2.3.8</version>
    </dependency>
    
  2. Smaller change

    String encoding = Base64.encodeBytes ((user + ":" + passwd).getBytes());
    
GabrielOshiro
  • 7,986
  • 4
  • 45
  • 57
lynhnn
  • 41
  • 1
3

for HttpClient always use HttpRequestInterceptor for example

httclient.addRequestInterceptor(new HttpRequestInterceptor() {
    public void process(HttpRequest arg0, HttpContext context) throws HttpException, IOException {
        AuthState state = (AuthState) context.getAttribute(ClientContext.TARGET_AUTH_STATE);
        if (state.getAuthScheme() == null) {
            BasicScheme scheme = new BasicScheme();
            CredentialsProvider credentialsProvider = (CredentialsProvider) context.getAttribute(ClientContext.CREDS_PROVIDER);
            Credentials credentials = credentialsProvider.getCredentials(AuthScope.ANY);
            if (credentials == null) {
                System.out.println("Credential >>" + credentials);
                throw new HttpException();
            }
            state.setAuthScope(AuthScope.ANY);
            state.setAuthScheme(scheme);
            state.setCredentials(credentials);
        }
    }
}, 0);
richsage
  • 26,912
  • 8
  • 58
  • 65
EngrSofty
  • 71
  • 7