Generic Top

I just announced the new Learn Spring course, focused on the fundamentals of Spring 5 and Spring Boot 2:


1. Overview

This tutorial will illustrate how to configure Basic Authentication on the Apache HttpClient 4.

If you want to dig deeper and learn other cool things you can do with the HttpClient – head on over to the main HttpClient tutorial.

Further reading:

HttpAsyncClient Tutorial

HttpAsyncClient Tutorial - send a basic GET request, use the multi-threaded client, set up the client with SSL as well as with a proxy, and finally - do authentication.

Advanced HttpClient Configuration

HttpClient configurations for advanced use cases.

2. Basic Authentication With the API

Let's start with the standard way of configuring Basic Authentication on the HttpClient – via a CredentialsProvider:

CredentialsProvider provider = new BasicCredentialsProvider();
UsernamePasswordCredentials credentials
 = new UsernamePasswordCredentials("user1", "user1Pass");
provider.setCredentials(AuthScope.ANY, credentials);
HttpClient client = HttpClientBuilder.create()

HttpResponse response = client.execute(
int statusCode = response.getStatusLine()
assertThat(statusCode, equalTo(HttpStatus.SC_OK));

As we can see, creating the client with a credentials provider to set it up with Basic Authentication is not difficult.

Now, to understand what HttpClient will actually do behind the scenes, we'll need to look at the logs:

# ... request is sent with no credentials
[main] DEBUG ... - Authentication required
[main] DEBUG ... - localhost:8080 requested authentication
[main] DEBUG ... - Authentication schemes in the order of preference: 
  [negotiate, Kerberos, NTLM, 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 Digest authentication scheme not available
[main] DEBUG ... - Selected authentication options: [BASIC]
# ... the request is sent again - with credentials

The entire Client-Server communication is now clear:

  • the Client sends the HTTP Request with no credentials
  • the Server sends back a challenge
  • the Client negotiates and identifies the right authentication scheme
  • the Client sends a second Request, this time with credentials

3. Preemptive Basic Authentication

Out of the box, the HttpClient doesn't do preemptive authentication. Instead, this has to be an explicit decision made by the client.

First, we need to create the HttpContext – pre-populating it with an authentication cache with the right type of authentication scheme pre-selected. This will mean that the negotiation from the previous example is no longer necessary – Basic Authentication is already chosen:

HttpHost targetHost = new HttpHost("localhost", 8082, "http");
CredentialsProvider credsProvider = new BasicCredentialsProvider();
  new UsernamePasswordCredentials(DEFAULT_USER, DEFAULT_PASS));

AuthCache authCache = new BasicAuthCache();
authCache.put(targetHost, new BasicScheme());

// Add AuthCache to the execution context
HttpClientContext context = HttpClientContext.create();

Now we can use the client with the new context and send the pre-authentication request:

HttpClient client = HttpClientBuilder.create().build();
response = client.execute(

int statusCode = response.getStatusLine().getStatusCode();
assertThat(statusCode, equalTo(HttpStatus.SC_OK));

Let's look at the logs:

[main] DEBUG ... - Re-using cached 'basic' auth scheme for http://localhost:8082
[main] DEBUG ... - Executing request GET /spring-security-rest-basic-auth/api/foos/1 HTTP/1.1
[main] DEBUG ... >> GET /spring-security-rest-basic-auth/api/foos/1 HTTP/1.1
[main] DEBUG ... >> Host: localhost:8082
[main] DEBUG ... >> Authorization: Basic dXNlcjE6dXNlcjFQYXNz
[main] DEBUG ... << HTTP/1.1 200 OK
[main] DEBUG ... - Authentication succeeded

Everything looks OK:

  • the “Basic Authentication” scheme is pre-selected
  • the Request is sent with the Authorization header
  • the Server responds with a 200 OK
  • Authentication succeeds

4. Basic Auth With Raw HTTP Headers

Preemptive Basic Authentication basically means pre-sending the Authorization header.

So, instead of going through the rather complex previous example to set it up, we can take control of this header and construct it by hand:

String auth = DEFAULT_USER + ":" + DEFAULT_PASS;
byte[] encodedAuth = Base64.encodeBase64(
String authHeader = "Basic " + new String(encodedAuth);
request.setHeader(HttpHeaders.AUTHORIZATION, authHeader);

HttpClient client = HttpClientBuilder.create().build();
HttpResponse response = client.execute(request);

int statusCode = response.getStatusLine().getStatusCode();
assertThat(statusCode, equalTo(HttpStatus.SC_OK));

Let's make sure this is working correctly:

[main] DEBUG ... - Auth cache not set in the context
[main] DEBUG ... - Opening connection {}->http://localhost:8080
[main] DEBUG ... - Connecting to localhost/
[main] DEBUG ... - Executing request GET /spring-security-rest-basic-auth/api/foos/1 HTTP/1.1
[main] DEBUG ... - Proxy auth state: UNCHALLENGED
[main] DEBUG ... - http-outgoing-0 >> GET /spring-security-rest-basic-auth/api/foos/1 HTTP/1.1
[main] DEBUG ... - http-outgoing-0 >> Authorization: Basic dXNlcjE6dXNlcjFQYXNz
[main] DEBUG ... - http-outgoing-0 << HTTP/1.1 200 OK

So, even though there is no auth cache, Basic Authentication still works correctly and we receive 200 OK.

5. Conclusion

This article illustrated various ways to set up and use basic authentication with the Apache HttpClient 4.

As always, the code presented in this article is available over on Github. This is a Maven based project, so it should be easy to import and run as it is.

Generic bottom

I just announced the new Learn Spring course, focused on the fundamentals of Spring 5 and Spring Boot 2:

Inline Feedbacks
View all comments
6 years ago

Thank you

This resolved my problem with NTLM Authentication, now I just need to consume wsdl service with CXF.

Eugen Paraschiv
6 years ago
Reply to  TowiPanda

Hey Towi – glad you found it useful. Cheers,

5 years ago

Hi Eugene, even with the second approach I can see server first responded with “HTTP/1.1 401 Unauthorized” and then server challenges again. why it is so. what I am missing?

Eugen Paraschiv
5 years ago
Reply to  Nirmal

Well, it depends – you’ll have to enable the extra logging that the HttpClient gives you and carefully study it to understand the entire communication. Depending on that and based on what the server responds with – you should be able to figure out the problem. Otherwise, with the limited info here – I’d say that you’re simply not providing the right authentication information that the server challenged you with.
Hope it helps. Cheers,

Lajos Incze
Lajos Incze
5 years ago

i would use iso-8859-1 (as the “most common”, quasi standard encoding scheme accepted by most browser, see ), instead of ascii at the direct header manipulation.

Eugen Paraschiv
5 years ago
Reply to  Lajos Incze

That makes sense, as ISO-8859-1 is can do more. I was of the impression that it’s mostly European, but since Firefox uses it by default – it’s probably not. Cheers,

4 years ago

Hi Eugen,
I successfully done HTTP BASIC auth with GET following this article.
But failed to do HTTP BASIC authentication with POST method.
Can you please help me with this. How can I get in touch with you.

Eugen Paraschiv
4 years ago
Reply to  ImTiaZ

Generally speaking, POST should work the same way.
And to answer your question about getting in touch – email is the best option. If you’re on the list, just reply to any of the emails you get – these go right into my inbox. Cheers,

Rajib Biswas
Rajib Biswas
4 years ago

Hi Eugen,
When I try to use non-preemptive basic authentication for HTTP POST request with attachment, it fails. Basically the http client does not include the mime attachment in the subsequent request in response to 401 from server.

Eugen Paraschiv
4 years ago
Reply to  Rajib Biswas

Hey Rajib – that’s an interesting scenario, but it’s also not something that can really be diagnosed here in the comments. My suggestion is to open a StackOverflow question (with an actual failing test that can be run) – and email me the link. Cheers,

Rajib Biswas
Rajib Biswas
4 years ago

Hi Eugen,
Thanks for your reply. Actually I have identified the issue, it was not an issue with HttpClient code. We have extended some client code, which was causing the issue. Thanks for your reply though.

Comments are closed on this article!