50

Been elaborating a bit with HttpClient for building a rest client. But I can't figure out, nor find any examples on how to authenticate towards the server. Most likely I will use basic aut, but really any example would be appreciated.

In earlier versions (which has examples online) you did:

HttpClient client = new HttpClient("http://localhost:8080/ProductService/");
client.TransportSettings.Credentials =
    new System.Net.NetworkCredential("admin", "admin");

However the TransportSettings property no longer exists in version 0.3.0.

Tomas
  • 1,725
  • 2
  • 18
  • 27

8 Answers8

110

All these are out of date. The final way to do it is as follows:

var credentials = new NetworkCredential(userName, password);
var handler = new HttpClientHandler { Credentials = credentials };

using (var http = new HttpClient(handler))
{
    // ...
}
Duncan Smart
  • 31,172
  • 10
  • 68
  • 70
  • 8
    I'm using VS2013 and .NET 4.5 The authorization header is not being set. I can only set the header directly through the property. What else could I be missing? – Alex Oct 20 '13 at 02:22
  • 8
    @Alex try setting `HttpClientHandler.PreAuthenticate = true` http://msdn.microsoft.com/en-us/library/system.net.http.httpclienthandler.preauthenticate.aspx – Duncan Smart Oct 20 '13 at 21:46
  • Awesome. @DuncanSmart deserves one more +1 – M.S. Dec 27 '17 at 12:12
17

The HttpClient library did not make it into .Net 4. However it is available here http://nuget.org/List/Packages/HttpClient. However, authentication is done differently in this version of HttpClient.

var httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Authorization 
                   = new AuthenticationHeaderValue("basic","...");

or

var webRequestHandler = new WebRequestHandler();
CredentialCache creds = new CredentialCache();
creds.Add(new Uri(serverAddress), "basic",
                        new NetworkCredential("user", "password"));
webRequestHandler.Credentials = creds;
var httpClient = new HttpClient(webRequestHandler);

And be warned, this library is going to get updated next week and there are minor breaking changes!

Darrel Miller
  • 139,164
  • 32
  • 194
  • 243
  • Yupp, sorry for being confusing. that's the version I got, the one from nuget. – Tomas Sep 12 '11 at 12:53
  • 1
    I played around with that, but I couldn't seem to get that to work. But as I understand, the "..." should be uname:pwd base64 encoded? – Tomas Sep 12 '11 at 12:54
  • Hmm... thought I had it working, but couldnt get it working with basic auth and preemptive auth... thanks for the guidance. – Tomas Sep 13 '11 at 10:13
  • Thanks, this proved useful for me, too. Only thing I would add is that some servers are case sensitive for their headers and prefer "Basic" over "basic". (Just discovered this myself) – Program.X Nov 13 '12 at 17:14
9

I tried Duncan's suggestion, but it didn't work in my case. I suspect it was because the server I was integrating with, didn't send a challenge or ask for authentication. It just refused my requests, because I didn't supply an Authorization header.

So I instead did the following:

using (var client = new HttpClient())
{
    var encoding = new ASCIIEncoding();
    var authHeader = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(encoding.GetBytes(string.Format("{0}:{1}", "username", "password"))));
    client.DefaultRequestHeaders.Authorization = authHeader;
    // Now, the Authorization header will be sent along with every request, containing the username and password.
}

Notice that the example here only works with Basic authentication.

Dan Friedman
  • 4,941
  • 2
  • 41
  • 65
René
  • 9,880
  • 4
  • 43
  • 49
3

As of .NET 4.8, .NET core 3.1 and .NET Standard 2.0 they recommend using both HttpClient and CredentialCache. Something like this:

const string basicAuthUser = @"myUser";
const string basicAuthPass = @"myPass";
const string host = @"https://my.host.com";
const string path = @"/api";

using (var httpClientHandler = new HttpClientHandler()) {
    httpClientHandler.PreAuthenticate = true;
    httpClientHandler.UseDefaultCredentials = true;

    var basicCredCache = new CredentialCache();
    var basicCredentials = new NetworkCredential(basicAuthUser, basicAuthPass);
    basicCredCache.Add(new Uri(new Uri(host), path), "Basic", basicCredentials);
    httpClientHandler.Credentials = basicCredCache;

    using (var client = new HttpClient(httpClientHandler)) {
        client.BaseAddress = new Uri(host);
        using (var request = new HttpRequestMessage(HttpMethod.Get /*HttpMethod.Post*/, path)) {
            //
            // Send request here
            //
        }
    }
}

EDIT: Note that wrapping HttpClient into using may lead to Socket exhaustion under high load. However keeping HttpClient as singleton may lead to other problems such as stale DNS issue. Start reading this long story from here.

Anton Krouglov
  • 3,077
  • 2
  • 29
  • 50
1

For what it is worth, nothing using HttpClientHandler worked, at least not for trying to make an authenticated call to the CouchDB API that requires server admin credentials.

This worked for me:

using( var client = new HttpClient() )
{
    var byteArray = Encoding.ASCII.GetBytes("MyUSER:MyPASS");
    client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(byteArray));
    ....
}

As outlined in the answer here:

How to use credentials in HttpClient in c#?

Community
  • 1
  • 1
ChrisCW
  • 520
  • 5
  • 5
1

I believe this is a bit old, but for anyone looking for an updated answer, I used this code when I built my test server:

        using (var client = new HttpClient())
        {
            client.BaseAddress = new Uri("http://myServer/api/Person");
            client.DefaultRequestHeaders.Accept.Clear();
            client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
            var byteArray = Encoding.ASCII.GetBytes($"{UserName}:{ApiPassword}");
            client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", Convert.ToBase64String(byteArray));

Or this works too:

            using (var http = new HttpClient())
            {
                // byteArray is username:password for the server
                var byteArray = Encoding.ASCII.GetBytes("myUserName:myPassword");
                http.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", Convert.ToBase64String(byteArray));
                string uri = "http://myServer/api/people" ;
                var response = await http.GetStringAsync(uri);
                List<Person> agencies = JsonConvert.DeserializeObject<List<Person>>(response);
                foreach (Person person in people)
                {
                    listBox1.Items.Add(person.Name);
                }
            }
GaryP
  • 223
  • 2
  • 13
0

I just downloaded 0.3.0 it has indeed be removed. It's now on HttpClientChannel

HttpClient client = new HttpClient(...);
var channel = new HttpClientChannel();
channel.Credentials = new NetworkCredential(...);
client.Channel = channel;

If not explicitly specified it uses a default instance of HttpClientChannel.

UPDATE: this is now invalid for .Net 4.5; see correct answer below: https://stackoverflow.com/a/15034995/58391

Community
  • 1
  • 1
TheCodeKing
  • 19,064
  • 3
  • 47
  • 70
  • That is an older version? I'm using 0.3.0 from nuget. – Tomas Sep 12 '11 at 13:43
  • @Thomas The one in RSK was a prototype. The nuget version was re-written, by another team, based on what they learned from the prototype. – Darrel Miller Sep 12 '11 at 14:38
  • @codekaizen this question refers to .Net 4, and was asked/answered before .NET 4.5 was released. – TheCodeKing Mar 13 '14 at 23:31
  • Sure, understood, but now that it shows up in search results for the same question, it's important to provide guidance to the current state of affairs. – codekaizen Apr 22 '14 at 16:02
-2

It only works when DefaultRequestHeaders is specified. It doesnt work any other way.