Overview

In this article, we will take a look at Apache HttpClient basic authentication between client and server with user name and password.
It will cover both non-preemptive and preemptive authentication using basic scheme.

Basic Authentication
To enable authentication between client and server with Apache HttpClient, following additional steps need to be followed other than sending a plain GET request or POST request.

1. Create a credentials provider.
2. Provide user name and password with UsernamePasswordCredentials object.
3. Provide host and port with which request needs to be authenticated using an object of AuthScope.
4. Provide objects created in Steps 2 and 3 to credentials provider with setCredentials() method.
5. Credentials provider object is given to the client using setDefaultCredentialsProvider() method while creating it.

Following example demonstrates basic authentication with Apache HttpClient.

This example uses httpbin basic auth service to send a request with user name and password.
It will return a success response if the user is authenticated along with 200 response code and 401 response code, if the authentication is not successful.

HttpGet get = new HttpGet(
                   "http://httpbin.org/basic-auth/foo/bar");
// create credentials provider
CredentialsProvider creds = new BasicCredentialsProvider();
// set host, port, username and password
creds.setCredentials(
         new AuthScope("httpbin.org", 80), 
         new UsernamePasswordCredentials("foo", "bar"));
// set credentials provider in client
CloseableHttpClient client = HttpClients.
                             custom().
                             setDefaultCredentialsProvider(creds).
                             build();
// send request
CloseableHttpResponse response = client.execute(get);
// read response
BufferedReader br = new BufferedReader(
                        new InputStreamReader(
                          response.getEntity().
                          getContent()));
String line = null;
while ((line = br.readLine()) != null) {
  System.out.println(line);
}

Following is the response

[main] DEBUG – Authentication succeeded
[main] DEBUG – Caching ‘basic’ auth scheme for http://httpbin.org:80
{
“authenticated”: true,
“user”: “foo”
}

If you carefully look at the previous logs given below

[main] DEBUG – Connection can be kept alive indefinitely
[main] DEBUG – Authentication required
[main] DEBUG – httpbin.org:80 requested authentication
[main] DEBUG – Authentication schemes in the order of preference: [Negotiate, Kerberos, NTLM, CredSSP, Digest, Basic]
[main] DEBUG – Challenge for Negotiate authentication scheme not available
[main] DEBUG – Challenge for Kerberos authentication scheme not available
[main] DEBUG – Challenge for NTLM authentication scheme not available
[main] DEBUG – Challenge for CredSSP authentication scheme not available
[main] DEBUG – Challenge for Digest authentication scheme not available
[main] DEBUG – Selected authentication options: [BASIC [complete=true]]
[main] DEBUG – Executing request GET /basic-auth/foo/bar HTTP/1.1
[main] DEBUG – Target auth state: CHALLENGED
[main] DEBUG – Generating response to an authentication challenge using basic scheme

which shows that first the client tries to connect to the server.
Server then requests for authentication(highlighted lines), the client then selects the authentication scheme and authenticates itself by sending another request.

This approach has an overhead of creating connection before authentication and sending an extra request.

To reduce these overheads, HttpClient provides an option of Preemptive authentication as explained below.

Preemptive Basic Authentication
In preemptive authentication, the client tries to authenticate itself before the server sends unauthorized response.
This is generally preferred to reduce load over the network since it prevents sending duplicate requests by the client.

For preemptive authentication in Apache HttpClient, we need to perform following additional steps, apart from basic authentication explained in the previous section :

1. Create a cache object. This cache object must contain the target host(or server address) and scheme objects.
Cache object is of type BasicAuthCache.
2. Target host is specified using an object of HttpHost.
3. Since we are using basic authentication, an object of BasicScheme is created.
4. Finally, create an object of HttpClientContext, which is provided to the client while sending request with execute() method.

Below is the code example based on these steps for performing preemptive basic authentication.

HttpGet get = new HttpGet(
                  "http://httpbin.org/basic-auth/foo/bar");
CredentialsProvider creds = new BasicCredentialsProvider();
creds.setCredentials(
         new AuthScope("httpbin.org", 80), 
         new UsernamePasswordCredentials("foo", "bar"));
CloseableHttpClient client = HttpClients.
                             custom().
                             setDefaultCredentialsProvider(creds).
                             build();
// create cache
AuthCache cache = new BasicAuthCache();
// define scheme
BasicScheme scheme = new BasicScheme();
// define host
HttpHost target = new HttpHost("httpbin.org", 80);
// associate host and scheme with cache
cache.put(target, scheme);
// define context
HttpClientContext context = HttpClientContext.create();
// set cache in context
context.setAuthCache(cache);
// provide context to client
CloseableHttpResponse response = client.execute(get, context);
BufferedReader br = new BufferedReader(
                        new InputStreamReader(
                        response.getEntity().
                        getContent()));
String line = null;
while ((line = br.readLine()) != null) {
  System.out.println(line);
}

The only difference between basic authentication and preemptive authentication is that the latter
1. Creates an authentication scheme and adds it to AuthCache.
2. Creates a context, provides it the auth cache created in Step 1.
3. Provides this context to client object while sending request.

So, for preemptive authentication, you need to add below extra lines of code

// create an auth cache
AuthCache cache = new BasicAuthCache(); 
// create a scheme
BasicScheme scheme = new BasicScheme(); 
// add scheme to cache
cache.put(target, scheme); 
// create context
HttpClientContext context = HttpClientContext.create(); 
// set cache in context
context.setAuthCache(cache); 
// provide context to client
CloseableHttpResponse response = client.execute(get, context);

Look at the output logs

[main] DEBUG – Re-using cached ‘basic’ auth scheme for http://httpbin.org:80
[main] DEBUG – Connection request: apache-httpclient-basic-authentication-java[total available: 0; route allocated: 0 of 2; total allocated: 0 of 20]
[main] DEBUG – Connection leased: [id: 0]apache-httpclient-basic-authentication-java[total available: 0; route allocated: 1 of 2; total allocated: 1 of 20]
[main] DEBUG – Opening connection {}->http://httpbin.org:80
[main] DEBUG – Connecting to httpbin.org/44.195.242.112:80
[main] DEBUG – Connection established 192.168.29.187:53595<->44.195.242.112:80
[main] DEBUG – Executing request GET /basic-auth/foo/bar HTTP/1.1

From the logs, it is clear that the client directly authenticates itself using basic scheme.

Hope the article was useful.