How do I pass Basic Auth to a RESTful service in c#? - c#

How do I call a RESTful service and pass in basic auth. This is username and password along with authorization basic.
using (var httpClient = new HttpClient())
{
//var request = new StringContent(messageBody);
//request.Headers.ContentType = new MediaTypeHeaderValue("application/json");
httpClient.BaseAddress = new Uri(serviceUrl);
httpClient.DefaultRequestHeaders.Accept.Clear();
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var credentials = Encoding.ASCII.GetBytes("myadmin:mypassword");
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(credentials));
//var response = await httpClient.PostAsJsonAsync(serviceUrl, customer);
HttpResponseMessage response = await httpClient.PostAsJsonAsync("url here", customer);
}

You have to concatenate the username and the password with a colon, encode the value to base64 and then add this value to the Authorization header with "Basic" scheme.

Related

Httpclient with 2 headers requests

I need to connect to editor's software PHP Api Post Json and I need to add in a header for authentication:
"Token" + key
"Content-Type", "application/json"
I have my content
var content = new StringContent(JsonConvert.SerializeObject(dtu, Formatting.Indented, new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Ignore
}));
ByteArrayContent(System.Text.Encoding.UTF8.GetBytes(content));
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
I then try to connect to the API
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(baseurl);
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Token", config.readStringKey("token"));
var result = client.PostAsync(baseurl, content)
.ResultContent.ReadAsStringAsync();
}
But I need to add the second line in headers.AuthenticationHeaderValue like
Screen capture https://imgur.com/a/UPU18sj
How do I do this?
You could use default request headers if reciever allows it:
// depending on token encoding you can add 'Token' to default headers dictionary. in this case: a bearer token
client.DefaultRequestHeaders.Add("Authorization", $"Bearer {token}"));
client.DefaultRequestHeaders.Add("content-type", "application/json"));

How to authenticate to Maximo 7.6 with .NET Core 3.1?

I'm not able to authenticate to get LtpaToken2 and JSESSIONID. Here is the code:
string url = "http://maximo.local/maximo/"; //http://maximo.local/maximo/j_security_check?j_username=admin&j_password=admin
string uri = "oslc/login";
using (HttpClient client = new HttpClient())
{
client.BaseAddress = new Uri(url);
string username = "admin";
string password = "admin";
client.DefaultRequestHeaders.Add($"Authorization", $"Basic {Base64Encode($"{username}:{password}")}");
string paramentros = "";
var response = client.PostAsync(uri, new StringContent(paramentros, Encoding.UTF8, "application/json")).Result;
if (response.IsSuccessStatusCode)
{
var jsonString = await response.Content.ReadAsStringAsync();
}
What could be wrong?
Does your Maximo store the username and password?
Native Authentication in Maximo uses a header to log in through the rest api, but it's not as you have it.
So you want to have the header maxauth and then the value is the base64 encoded userid:password.

How do you use Basic Authentication with System.Net.Http.HttpClient?

I'm trying to implement a rest client in c# .net core that needs to first do Basic Authentication, then leverage a Bearer token in subsequent requests.
When I try to do Basic Authentication in combination with client.PostAsync with a FormUrlEncodedContent object, I'm getting an exception:
System.InvalidOperationException occurred in System.Net.Http.dll: 'Misused header name. Make sure request headers are used with HttpRequestMessage, response headers with HttpResponseMessage, and content headers with HttpContent objects.'
//setup reusable http client
HttpClient client = new HttpClient();
Uri baseUri = new Uri(url);
client.BaseAddress = baseUri;
client.DefaultRequestHeaders.Clear();
client.DefaultRequestHeaders.ConnectionClose = true;
//Post body content
var values = new List<KeyValuePair<string,string>>();
values.Add(new KeyValuePair<string, string>("grant_type", "client_credentials"));
var content = new FormUrlEncodedContent(values);
//Basic Authentication
var authenticationString = $"{clientId}:{clientSecret}";
var base64EncodedAuthenticationString = Convert.ToBase64String(System.Text.ASCIIEncoding.ASCII.GetBytes(authenticationString));
content.Headers.Add("Authorization", $"Basic {base64EncodedAuthenticationString}");
//make the request
var task = client.PostAsync("/oauth2/token",content);
var response = task.Result;
response.EnsureSuccessStatusCode();
string responseBody = response.Content.ReadAsStringAsync().Result;
Console.WriteLine(responseBody);
Exception has occurred: CLR/System.InvalidOperationException
An unhandled exception of type 'System.InvalidOperationException' occurred in System.Net.Http.dll: 'Misused header name. Make sure request headers are used with HttpRequestMessage, response headers with HttpResponseMessage, and content headers with HttpContent objects.'
at System.Net.Http.Headers.HttpHeaders.GetHeaderDescriptor(String name)
at System.Net.Http.Headers.HttpHeaders.Add(String name, String value)
It looks like you can't use PostAsync and have access to mess with the Headers for authentication. I had to use an HttpRequestMessage and SendAsync.
//setup reusable http client
HttpClient client = new HttpClient();
Uri baseUri = new Uri(url);
client.BaseAddress = baseUri;
client.DefaultRequestHeaders.Clear();
client.DefaultRequestHeaders.ConnectionClose = true;
//Post body content
var values = new List<KeyValuePair<string, string>>();
values.Add(new KeyValuePair<string, string>("grant_type", "client_credentials"));
var content = new FormUrlEncodedContent(values);
var authenticationString = $"{clientId}:{clientSecret}";
var base64EncodedAuthenticationString = Convert.ToBase64String(System.Text.ASCIIEncoding.ASCII.GetBytes(authenticationString));
var requestMessage = new HttpRequestMessage(HttpMethod.Post, "/oauth2/token");
requestMessage.Headers.Authorization = new AuthenticationHeaderValue("Basic", base64EncodedAuthenticationString);
requestMessage.Content = content;
//make the request
var task = client.SendAsync(requestMessage);
var response = task.Result;
response.EnsureSuccessStatusCode();
string responseBody = response.Content.ReadAsStringAsync().Result;
Console.WriteLine(responseBody);
It's not a good practice to create HttpClients explicitly from your calling code.
Please use HttpClientFactory that simplifies a lot of things.
However, if you want to use basic authentication, just create an HttpRequestMessage and add the following header:
var request = new HttpRequestMessage(HttpMethod.Post, getPath)
{
Content = new FormUrlEncodedContent(values)
};
request.Headers.Authorization = new BasicAuthenticationHeaderValue("username", "password");
// other settings
If you decide to use a recommended IHttpClientFactory it's even simpler:
serviceCollection.AddHttpClient(c =>
{
c.BaseAddress = new Uri("your base url");
c.SetBasicAuthentication("username", "password");
})
Don't encode the whole authentication string - encode the "Username:Password" expression and append the result to the "Basic " prefix.
var authenticationString = $"{clientId}:{clientSecret}";
var base64EncodedAuthenticationString = Convert.ToBase64String(System.Text.ASCIIEncoding.UTF8.GetBytes(authenticationString));
content.Headers.Add("Authorization", "Basic " + base64EncodedAuthenticationString);
Also, consider using just ASCII encoding - the UTF8 may not be understood by the server unless you add a charset declaration to the header.
Wikipedia seems to cover this quite well.
The specific problem is this line (below)
content.Headers.Add("Authorization", $"Basic {base64EncodedAuthenticationString}");
This fails because HttpContent.Headers (System.Net.Http.Headers.HttpContentHeaders) is only for headers that are content-specific, such as Content-Type, Content-Length, and so on.
You've stated that you can't use DefaultRequestHeaders because you only need it for a single request - but you also can't use it with PostAsync - only SendAsync provided you construct the HttpRequestMessage yourself, as per your own answer and #NeilMoss' answer - but you could use an extension-method in future.
But for the benefit of other readers, another alternative is to add a new extension method based on the existing PostAsync, which is actually really simple (only 3 lines!):
public Task<HttpResponseMessage> PostAsync( this HttpClient httpClient, Uri requestUri, HttpContent content, String basicUserName, String basicPassword, String? challengeCharSet = null, CancellationToken cancellationToken = default )
{
if( basicUserName.IndexOf(':') > -1 ) throw new ArgumentException( message: "RFC 7617 states that usernames cannot contain colons.", paramName: nameof(basicUserName) );
HttpRequestMessage httpRequestMessage = new HttpRequestMessage( HttpMethod.Post, requestUri );
httpRequestMessage.Content = content;
//
Encoding encoding = Encoding.ASCII;
if( challengeCharSet != null )
{
try
{
encoding = Encoding.GetEncoding( challengeCharSet );
}
catch
{
encoding = Encoding.ASCII;
}
}
httpRequestMessage.Headers.Authorization = new AuthenticationHeaderValue(
scheme : "Basic",
parameter: Convert.ToBase64String( encoding.GetBytes( userName + ":" + password ) )
);
return SendAsync( httpRequestMessage, cancellationToken );
}
Usage:
HttpClient httpClient = ...
using( HttpResponseMessage response = await httpClient.PostAsync( uri, content, basicUserName: "AzureDiamond", basicPassword: "hunter2" ).ConfigureAwait(false) )
{
// ...
}
Just something to add that I struggled with, which I only experienced with Basic authentication endpoints. If you add Json as StringContent then it adds a charset=utf-8, this often return a BadRequest 400.
Here is the code I got to fix this: reference:
https://dzone.com/articles/httpclient-how-to-remove-charset-from-content-type
using (var client = new HttpClient())
using (var content = new StringContent(ParseJSON(data), Encoding.Default, "application/json"))
{
//Remove UTF-8 Charset causing BadRequest 400
content.Headers.ContentType.CharSet = "";
var clientId = "client";
var clientSecret = "secret";
var authenticationString = $"{clientId}:{clientSecret}";
var base64EncodedAuthenticationString = Convert.ToBase64String(System.Text.ASCIIEncoding.UTF8.GetBytes(authenticationString));
client.DefaultRequestHeaders.TryAddWithoutValidation(authHeader, authorization);
var response = await client.PostAsync(url, content);
return response;
}
I have resolve this by using below code, that serve my purpose also. Added Code for both Get/Post, this will help you. Moreover I have added one more Header key. So to pass extra data to header. Hope that will resolve your issue.
class Program {
private static readonly string Username = "test";
private static readonly string Password = "test#123";
static void Main(string[] args) {
var response = Login();
}
public static async Task Login()
{
var anotherKey ="test";
HttpClient httpClient = new HttpClient
{
BaseAddress = new Uri("https://google.com/")
};
httpClient.DefaultRequestHeaders.Add($"Authorization", $"Basic {Base64Encode($"{Username}:{Password}")}");
httpClient.DefaultRequestHeaders.Add($"anotherKey", $"{anotherKey}");
HttpResponseMessage httpResponseMessage = await httpClient.GetAsync("user/123").ConfigureAwait(false);
// For Get Method
var response= await httpResponseMessage.Content.ReadAsStringAsync().ConfigureAwait(false);
// For Post Method
User user = new User (1,"ABC");
HttpResponseMessage httpResponseMessage = await httpClient.PostAsJsonAsync("/post", user).ConfigureAwait(false);
UserDetail userDetail = await httpResponseMessage.Content.ReadAsAsync<UserDetail>().ConfigureAwait(false);
}
}
Using .NET 6, I use the HttpClient.DefaultRequestHeaders.Authorization property to set the Authorization header.
// This example will send a signing request to the RightSignature API
var api = "https://api.rightsignature.com/public/v2/sending_requests";
// requestJson is the serialized JSON request body
var contentData = new StringContent(requestJson, Encoding.UTF8, "application/json");
// Instantiate client (for testing), use Microsoft's guidelines in production
var client = new HttpClient();
// Use basic auth, the token has already been converted to base64
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", tokenB64);
try
{
var response = await client.PostAsync(api, contentData);
}
...
Good luck!

Can't authenticate correctly with headers (HttpClient)

I've checking many forums but I can't make it work. I'm trying to authenticate with headers to an url that will return a JSON string if authentication were successful. In Postman I simply used Get method with username and password in header to get the JSON data. What changes do I need to make my following C# code achieve same thing? I think I even failed to add username and password into headers.
public async Task<string> LogMeIn(string username, string password)
{
var client = new HttpClient {
BaseAddress = new Uri("http://x.com")
};
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var content = new FormUrlEncodedContent(new[] {
new KeyValuePair<string,string>("grant_type","password"),
new KeyValuePair<string,string>("Username ", username),
new KeyValuePair<string,string>("Password", password)
});
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
var response = await client.PostAsync("/login", content); //should it be GetAsync?
var jsonResp = await response.Content.ReadAsStringAsync();
var jsonResult = JsonConvert.DeserializeObject<JsonResult>(jsonResp); //JsonResult = class for json
return jsonResult.token;
}
}

CRM 2016 web apis with C#

We have CRM 2016 on premise and want to consume the API using c# :
var credentials = new NetworkCredential(username, password);
HttpClient client = new HttpClient(new HttpClientHandler() {Credentials = credentials});
client.BaseAddress = new Uri("https://xxx.elluciancrmrecruit.com/api/data/v8.0/datatel_events");
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = client.GetAsync("datatel_events?$orderby=datatel_eventname").Result;
if (response.IsSuccessStatusCode)
{
var yourcustomobjects = response.Content.ReadAsStringAsync();
}
else
{
//Something has gone wrong, handle it here
}
But it always return HTML page says try later instead of the json response.
You should query the OData endpoint to get the information you are looking for assuming date1_events is a custom entity (although the naming convention seems to be off).
As an example to query contacts:
var credentials = new NetworkCredential(username, password);
var client = new HttpClient(new HttpClientHandler() {Credentials = credentials})
{
BaseAddress = new Uri("https://xxx.elluciancrmrecruit.com/api/data/v8.0/")
};
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var response = client.GetAsync("accounts?$top=1").Result;
if (response.IsSuccessStatusCode)
{
var yourcustomobjects = response.Content.ReadAsStringAsync();
}

Categories