-1

I'm trying to connect to URL using C#.

Basically I'm trying to do the same thing as CURL :

curl -i -k --user ABC..:XYZ.. --data "grant_type=client_credentials" https://www.example.com/oauth/token

Here is my C# code :

// Get the URL
string URL = "https://www.example.com/oauth/token";

//Create the http client
HttpClient client = new HttpClient();
HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Post, URL);
requestMessage.Headers.Add("contentType", "application/x-www-form-urlencoded");
requestMessage.Headers.Add("data", "grant_type=client_credentials");
requestMessage.Headers.Add("user", "ABC..:XYZ..");

//Connect to the URL
HttpResponseMessage response = client.SendAsync(requestMessage).Result;

// Get the response
string Output = response.Content.ReadAsStringAsync().Result;

Curl code works great. And I get a 200 status response. However in C#, I'm having the response : 401, Unauthorized. It seems like client id and key are not provided in the correct format.

Does anyone know what is missing in my C# code please ?

Thanks, cheers

Thomas Carlton
  • 5,344
  • 10
  • 63
  • 126
  • Drop the headers. Also, basic auth should be a property of the client – theMayer Nov 18 '19 at 03:04
  • @theMayer do you mean I have to delete the headers ? If so where should I put the client credentials please ? – Thomas Carlton Nov 18 '19 at 03:05
  • Are you trying to do a get? You can’t post data with a get. I think you need a post. – theMayer Nov 18 '19 at 03:06
  • @theMayer when I use Post, I'm getting the error : 401, Unauthorized – Thomas Carlton Nov 18 '19 at 03:07
  • I’m just trying to offer some troubleshooting suggestions. The error indicates the server is not happy with the request. If you’re doing a get and it expects a post, tbag would explain. – theMayer Nov 18 '19 at 03:07
  • `curl --data ...` will produce `POST` request, not `GET` – vasily.sib Nov 18 '19 at 03:18
  • @vasily.sib I corrected that, now I'm having the error : 401, Unauthorized. It seems like the user id and key are not provided in the correct format. Do you have an idea how to solve that please ? Thanks – Thomas Carlton Nov 18 '19 at 03:21
  • Your curl does a POST, not a GET. See https://stackoverflow.com/questions/30858890/how-to-use-httpclient-to-post-with-authentication –  Nov 18 '19 at 03:23
  • 1
    This is because `--user ABC..:XYZ..` is not the same as `requestMessage.Headers.Add("user", "ABC..:XYZ..");`, I will post an answer to explain more – vasily.sib Nov 18 '19 at 03:24

2 Answers2

4

Your curl command produce POST request, so to do the same thing in C# you need a HttpClient.PostAsync method.

Your data is application/x-www-form-urlencoded, so you can make your life easear by using FormUrlEncodedContent.

Your last problem is authentication. You should use AuthenticationHeaderValue for this.

So, here is you code sample, that should work:

var client = new HttpClient();

// HTTP Basic authentication
var authenticationHeaderBytes = Encoding.ASCII.GetBytes("ABC..:XYZ..");
var authenticationHeaderValue = Convert.ToBase64String(authenticationHeaderValue);
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", authenticationHeaderValue);

// POST content
var content = new FormUrlEncodedContent(
    new Dictionary<string, string> { { "grant_type", "client_credentials" } });

// make request
var response = await client.PostAsync("https://www.example.com/oauth/token", content);

Also, that there is common mistake of doing something like

using (var client = new HttpClient())
{
    // ...
}

Bad things will happen, don't do this. You may read more here. Long story short - you shouldn't create (and shouldn't allow) to many instances of HttpClient within your app.

vasily.sib
  • 3,871
  • 2
  • 23
  • 26
2

curl's --user can be expressed in c# as

requestMessage.Headers["Authorization"] = "Basic " + 
    Convert.ToBase64String(Encoding.ASCII.GetBytes("username:password"));

The grant type needs to be sent as content.

var content = new FormUrlEncodedContent(new[]
{
    new KeyValuePair<string, string>("grant_type", "client_credentials")
});
var result = await client.PostAsync(url, content);

You could also try sending username and password in the body.

using (HttpClient client = new HttpClient())
{
    var req = new HttpRequestMessage(HttpMethod.Post, new Uri(url));
    req.Content = new FormUrlEncodedContent(new Dictionary<string, string>
    {
        { "grant_type", "client_credentials" }, // or "password"
        { "username", username },
        { "password", password }
    });

    var response = await client.SendAsync(req);
    // No error handling for brevity
    var data = await response.Content.ReadAsStringAsync();

Finally you may or may not need to set the accept header.

request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));                
tymtam
  • 31,798
  • 8
  • 86
  • 126