7

When using the HttpClient in .net 4.5 to do basic authentication I'm finding that it's issuing 2 requests.

The first fails with a HTTP/1.1 401 Unauthorized and then it resends the request to which we get a HTTP/1.1 200 OK.

Any ideas on how to stop it from doing this?

var credential = new NetworkCredential 
{ 
    UserName = username, 
    Password = password 
}
var httpClientHandler = new System.Net.Http.HttpClientHandler
{
    Credentials = credential
};
httpClient = new HttpClient(httpClientHandler, true)
{
    BaseAddress = address
};
Ian Oakes
  • 10,153
  • 6
  • 36
  • 47

4 Answers4

5

Try setting this:

httpClientHandler.PreAuthenticate = true;

I think the very first request will still get the initial 401, but subsequent request to the same URI up to the last forward slash should always send the authentication headers without the 401.

Tobberoth
  • 9,327
  • 2
  • 19
  • 17
  • 2
    I thought that as well, but the documentation suggests that won't work - it will still not send authentication information for the first request. – Jon Skeet Nov 28 '13 at 07:23
  • Yeah, I saw the same thing, which makes me assume that there's no way to make HttpClient do this, unless you manually create the header for the initial request (which is obviously quite easy, but obnoxious to do). – Tobberoth Nov 28 '13 at 07:27
  • 1
    I tried PreAuthenticate = true, but it doesn't seem to change anything, I still get the 401 followed by a 200 – Ian Oakes Nov 28 '13 at 07:28
  • 2
    I can get it to work if I forgo using the NetworkCredentials class and add the following httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(Encoding.UTF8.GetBytes(username + ":" + password))); but that really sucks :) – Ian Oakes Nov 28 '13 at 07:30
  • @IanOakes Yeah, exactly. Unfortunately, I assume Microsoft has some reason to not allow PreAuthenticate to work its magic on the very first request... Why do you need to skip that initial 401 anyway? It's supposed to happen with basic authentication, can't you just work around it? – Tobberoth Nov 28 '13 at 07:32
  • We're getting hassled by the owner of the service, because they're logging all of these unauthorised attempts at their end. – Ian Oakes Nov 28 '13 at 07:36
  • 1
    Customer is always right, so I assume you can't just tell them to stop being idiots who log WWW-Authenticate calls ;). How about writing an extension method to HttpClient where you implement the code you posted above? That will work like you tested, while also looking clean in the code. – Tobberoth Nov 28 '13 at 07:42
1

You could try setting HttpClientHandler.PreAuthenticate as per Tobberoth's answer, although the documentation for that suggests it will only help after the very first request:

With the exception of the first request, the PreAuthenticate property indicates whether to send authentication information with subsequent requests to a Uri that matches the specific Uri up to the last forward slash without waiting to be challenged by the server.

It won't help for the very first request, but it may help to reduce the number of round trips after that.

Another thing to try is including "Authorization" in HttpClient.DefaultRequestHeaders. I'd be slightly surprised if that worked, but it's worth trying, at least.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • We still get 401's with PreAuthenitcate = true, but just not as many, running an integratation test shows that for 9 requests we still get 3 401 responses, whereas without this setting we would get 9. – Ian Oakes Nov 28 '13 at 07:45
  • 1
    @IanOakes Any chance the HttpClient was being disposed and therefore closing the connection. That would probably cause the the 401 dance again. – Darrel Miller May 27 '15 at 21:38
0

While looking for an answer to another problem I have with the NetworkCredentials I stumbled across two questions with answers that might be the ones you're looking for:

Here the answer says that at least WebRequest has the default behaviour of only sending the credentials after getting a 401. And here it seems that the solution might be using a CredentialCache.

I'm not sure if the CredentialCache works with the HttpClient, but if it doesn't you could switch to WebRequest or also WebClient, or maybe this information just brought you on the path to another solution.

Community
  • 1
  • 1
phlow
  • 122
  • 5
  • 12
0

The best to avoid the second call is to create and set Authorization header manually: https://stackoverflow.com/a/4346843/1143824

Saeed
  • 56
  • 9