44

I am trying to do the following curl (which works for me) in C# using HttpClient.

curl -X POST http://www.somehosturl.com \
     -u <client-id>:<client-secret> \
     -d 'grant_type=password' \
     -d 'username=<email>' \
     -d 'password=<password>' \
     -d 'scope=all

The C# Code:

HttpClientHandler handler = new HttpClientHandler { Credentials = new  
            System.Net.NetworkCredential ("my_client_id", "my_client_secret")
    };


    try
    {
        using(var httpClient = new HttpClient(handler))
        {
            var activationUrl = "www.somehosturl.com";

            var postData = "grant_type=password&username=myemail@myemail.com&password=mypass&scope=all";
            var content = new StringContent(postData, Encoding.UTF8, "application/x-www-form-urlencoded");

            var response = await httpClient.PostAsync(activationUrl, content);
            if(!response.IsSuccessStatusCode)
                return null;

            var result = await response.Content.ReadAsStringAsync();

            return result;
        }
    }
    catch(Exception)
    {
        return null;
    }

When executed, just crashes out, doesnt even catch the exception

Normally I am able to GET and POST perfectly fine, but whats throwing me off is how to set the auth stuff (client-id and client-secret)

John Saunders
  • 160,644
  • 26
  • 247
  • 397
Jesse
  • 2,674
  • 6
  • 30
  • 47
  • 2
    What do you mean by crashes? Are you running this inside VS? Did you turn on First Chance Exceptions? – Yuval Itzchakov Jun 16 '15 at 04:49
  • Take a look at this Stackoverflow post to see if it helps: http://stackoverflow.com/a/23914662/1337635 – joehanna Jun 16 '15 at 04:49
  • could you please post your code including method signature. – Taimur Khan Jun 16 '15 at 06:03
  • Try enabling CLRE (From VS: go to 'DEBUG', 'Exceptions', check the 'Common Language Runtime Exceptions' option ('Thrown' column) and press 'OK'. Then try to run your code again (this will only give you more information about the reason your app crashes, won't fix your problem, of course) – Nissim Jun 16 '15 at 07:01
  • 1
    Don't ever catch exceptions that way! You're just ignoring the exception without even finding out what kind of exception it is. You'd be better off just removing the try/catch block. At worse, add code to display the exception to yourself for troubleshooting purposes. – John Saunders Jun 16 '15 at 07:40
  • Visual Studio doesn't "just crash", nor do exceptions escape. Your code explicitly discards exceptions by using `catch(Exception){}`. It also ignores error codes by using `return null;` Fix the exception handling code, then post the stacktrace of the exception – Panagiotis Kanavos Jun 16 '15 at 07:45

3 Answers3

43

First you have to set the Authorization-Header with your <clientid> and <clientsecret>.

Instead of using StringContent you should use FormUrlEncodedContent as shown below:

var client = new HttpClient();
client.BaseAddress = new Uri("http://myserver");
var request = new HttpRequestMessage(HttpMethod.Post, "/path");

var byteArray = new UTF8Encoding().GetBytes("<clientid>:<clientsecret>");
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(byteArray));

var formData = new List<KeyValuePair<string, string>>();
formData.Add(new KeyValuePair<string, string>("grant_type", "password"));
formData.Add(new KeyValuePair<string, string>("username", "<email>"));
formData.Add(new KeyValuePair<string, string>("password", "<password>"));
formData.Add(new KeyValuePair<string, string>("scope", "all"));

request.Content = new FormUrlEncodedContent(formData);
var response = await client.SendAsync(request);
Alexander Zeitler
  • 11,919
  • 11
  • 81
  • 124
  • 3
    You should explain *why* this is an answer to the question. Do you want to say that on top of having to set the authentication header, the OP passes post data in the wrong way ? – Panagiotis Kanavos Jun 16 '15 at 09:04
  • Thanks Alexander, this works great! I am using Xamarin though so I couldn't use Encoding.ASCII, I had to use new UTF8Encoding().GetBytes(). – Jesse Jun 16 '15 at 20:48
  • 1
    Why do you use `client.DefaultRequestHeaders.Authorization` instead of `request.Headers.Authorization`? – Richard Marskell - Drackir Nov 06 '18 at 13:50
  • Can someone explain why need to change data to byteArray before passing to client.DefaultRequestHeaders.Authorization ? – dellos Mar 24 '22 at 02:46
  • @dellos Because `Convert.ToBase64String()` has no overload which accepts a string value. https://learn.microsoft.com/en-us/dotnet/api/system.convert.tobase64string?view=net-6.0 – Alexander Zeitler Mar 24 '22 at 07:05
  • @AlexanderZeitler, No I thought about why need to cast the ":" string to byteArray first then cast it back to string? Is it for a security concert? – dellos Mar 24 '22 at 07:54
  • 1
    @dellos The second cast is not a plain text string but a base64 encoded one. https://en.wikipedia.org/wiki/Basic_access_authentication – Alexander Zeitler Mar 24 '22 at 07:56
29

Try to place your credentials directly into the headers property of HttpClient.

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

       return await client.GetStringAsync(uri);
}
John Saunders
  • 160,644
  • 26
  • 247
  • 397
n.yakovenko
  • 1,957
  • 1
  • 16
  • 15
  • 1
    Can someone explain why need to change data to byteArray before passing to client.DefaultRequestHeaders.Authorization ? – dellos Mar 24 '22 at 02:48
5

See BasicAuthenticationHeaderValue

httpClient.DefaultRequestHeaders.Authorization
    = new BasicAuthenticationHeaderValue("login", "password");

Or use extensions from IdentityModel:

<PackageReference Include="IdentityModel" Version="4.0.0" />

var client = new HttpClient();
client.SetBasicAuthentication(login, password);
client.SetBearerToken(token);
Сергей
  • 171
  • 2
  • 4
  • 4
    You've written about `BasicAuthenticationHeaderValue` but provided link to `AuthenticationHeaderValue`, so your example is invalid in .Net 5. – Mikołaj Aug 26 '21 at 10:00
  • For IdentityModel, Bearer Authentication is different than Basic one. [https://stackoverflow.com/a/59670260/3142139] – M.Hassan Apr 29 '23 at 00:58