I am new to the C# world, and can't for the life of me figure out how to get around this error. I am trying to make a simple get request using a platform API key. I have built out the API connection in Google App Script on the same laptop, and it works fine, but when trying to build out the same API in C#, it is returning:
{StatusCode: 403, ReasonPhrase: 'Forbidden', Version: 1.1, Content: System.Net.Http.HttpConnectionResponseContent, Headers:
{
Date: Sun, 13 Mar 2022 02:41:29 GMT
Transfer-Encoding: chunked
Connection: close
CF-Chl-Bypass: 1
Permissions-Policy: accelerometer=(),autoplay=(),camera=(),clipboard-read=(),clipboard-write=(),fullscreen=(),geolocation=(),gyroscope=(),hid=(),interest-cohort=(),magnetometer=(),microphone=(),payment=(),publickey-credentials-get=(),screen-wake-lock=(),serial=(),sync-xhr=(),usb=()
Cache-Control: private, max-age=0, no-store, no-cache, must-revalidate, post-check=0, pre-check=0
X-Frame-Options: SAMEORIGIN
Expect-CT: max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"
Strict-Transport-Security: max-age=2592000
Server: cloudflare
CF-RAY: 6eb1692f8bd776c3-LHR
Content-Type: text/html; charset=utf-8
Expires: Thu, 01 Jan 1970 00:00:01 GMT
}}
The API documentation says:
"To authenticate against the API, include your API key in the 'Authorization' header, prefixed with 'Key ', in every request. Example: 'Authorization: Key yourapikey'"
And so, I have tried adding this to
a) the HttpClient via HttpClient.DefaultRequestHeaders.Authorization
b) the HttpClient via HttpClient.DefaultHeaders.Add
c) the HttpRequestMessage via HttpRequestMessage.Headers.Add
In each instance, the request URI looks good, as well as the headers, but still returning 403.
My current structure is:
// services
builder.Services.AddHttpClient("myplatform", c =>
{
c.BaseAddress = new Uri("https://seller-api.myplatform.com/v2/");
c.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
});
// controller
// constructor uses IHttpClientFactory
this._httpClient = clientFactory.CreateClient("myplatform");
// service
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Key", platformKey);
string endPoint = "offers" + CreateQueryString(pageNumber, pageSize);
// example endPoint: offers?page_number=1&page_size=100
var requestMsg = new HttpRequestMessage()
{
Method = HttpMethod.Get,
RequestUri = new Uri(httpClient.BaseAddress + endPoint)
};
try
{
var result = await httpClient.SendAsync(requestMsg);
}
catch (Exception ex)
{
}
Again, the content of the call works when calling through GoogleAppScript. What am I doing wrong in C#, and how can I correct this?
Not sure if this is all the information needed - let me know otherwise! Important to note, the target framework is .NET 6.0.
EDIT
As suggested by a comment around duplicate clients, I have removed the client factory. I am now creating a new HttpClient in the controller constructor, and passing this client to my service to do the GET request.
this._httpClient = new HttpClient();
Again, the client and the request message look well formed at time of request but still returning 403 error. Is there an issue with my VS22 client, or web client etc.?
Also, the call I am making successfully via Google AppScript is using UrlFetchApp. Not sure what is the issue here with the C# side..
EDIT2
Adding current GAS code for reference:
var url = 'https://seller-api.platform.com/v2';
var end_point = '/offers?';
var header = {
'Authorization': api_key
}
var params = {
'method': 'GET',
'headers': header
}
// call API
var page_query = 'page_number=' + page + '&page_size=' + maxItemsPerPage;
var full_url = url + end_point + page_query;
var response = UrlFetchApp.fetch(full_url, params);
The HTTP 403 Forbidden response status code indicates that the server understands the request but refuses to authorize it.
There are two ways add request headers when using HttpClient:
Add headers for all requests using HttpClient.DefaultRequestHeaders.
HttpClient = new HttpClient();
HttpClient.DefaultRequestHeaders.Add("Key", platformKey);
var response = await HttpClient.GetAsync(GetRandomNumberUrl);
response.EnsureSuccessStatusCode();
await response.Content.ReadAsStringAsync();
Add headers per request using HttpRequestMessage.Headers.
HttpClient = new HttpClient();
using (var request = new HttpRequestMessage(HttpMethod.Get, randomNumberUrl))
{
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", platformKey);
var response = await HttpClient.SendAsync(request);
response.EnsureSuccessStatusCode();
await response.Content.ReadAsStringAsync();
}
Your problem is here in this line:
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Key", platformKey);
your _httpClient and Authorization httpClient is not same instance.
Try this way:
HttpClient HttpClient = new HttpClient();
string url = "https://seller-api.platform.com/v2";
string end_point = "/offers?";
string api_key = "key here";
string page_query = "page_number=" + 10 + "&page_size=" + 20;
string full_url = url + end_point + page_query;
using (var request = new HttpRequestMessage(HttpMethod.Get, url))
{
request.Headers.Add("Authorization", api_key);
var response = await HttpClient.SendAsync(request);
response.EnsureSuccessStatusCode();
var m = await response.Content.ReadAsStringAsync();
}
Solution 2:
Try calling it like a browser :
HttpClient httpClient = new HttpClient();
string url = "https://gatewayt.whatever.com/chkt/request/request.php";
string end_point = "/offers?";
string api_key = "key here";
string page_query = "page_number=" + 10 + "&page_size=" + 20;
string full_url = url + end_point + page_query;
httpClient.DefaultRequestHeaders.TryAddWithoutValidation("Accept", "text/html,application/xhtml+xml,application/xml");
httpClient.DefaultRequestHeaders.TryAddWithoutValidation("Accept-Encoding", "gzip, deflate");
httpClient.DefaultRequestHeaders.TryAddWithoutValidation("User-Agent", "Mozilla/5.0 (Windows NT 6.2; WOW64; rv:19.0) Gecko/20100101 Firefox/19.0");
httpClient.DefaultRequestHeaders.TryAddWithoutValidation("Accept-Charset", "ISO-8859-1");
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Key", api_key);
var response = await httpClient.GetAsync(url);
response.EnsureSuccessStatusCode();
await response.Content.ReadAsStringAsync();
source: Request like browser Link1 Link2 Link3
Related
I spent a lot of time looking for an answer, but I didn't find it. I need to send a POST to an API using HTTPClient in C# in the following format:
POST endpoint URL
Content-Type: application/json
Authorization-User: email address
Authorization-Key: EMP-generated key
{
request body
}
Authorization-User and Authorization-Key are required in headers and cannot be replaced by username and password name.
When I use my code described below I got the exception in line client.DefaultRequestHeaders.Add: "Incorrect header name. Check if request headers are used with HttpRequestMessage, response headers with HttpResponseMessage and content headers with HttpContent objects".
Can someone help me?
My code:
var client = new HttpClient();fdaJsonCons ofdaJson = new fdaJsonCons();
fdaFilters oFdaFilter = new fdaFilters();
ofdaJson.filters = oFdaFilter;
string stJson = JsonConvert.SerializeObject(ofdaJson);
string vContentType = "application/json";
var content = new StringContent(JsonConvert.SerializeObject(stJson), Encoding.Default, "application/json");
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(vContentType));
client.DefaultRequestHeaders.Add("Content-Type", String.Format("Basic {0}", "application/json"));
client.DefaultRequestHeaders.Add("Authorization", String.Format("Authorization-User {0}", "my-email"));
client.DefaultRequestHeaders.Add("Authorization", String.Format("Authorization-Key {0}", "my-keyvalue"));
var result = await client.PostAsync(url, content);
var result_string = await result.Content.ReadAsStringAsync();
I am working with an API service that requires Content-Type to be set to application/json;charset=UTF-8.
If I make a request without the charset=UTF-8 I get a 406 - Not Acceptable.
I can make a call through Postman setting the Content-Type as required, but if I use my .Net Http Client I get the error:
System.FormatException: 'The format of value
'application/json;charset=UTF-8' is invalid.'
Is there anyway I can work around this validation and force the Http Client to accept the value?
UPDATE:
Here is my latest attempt,it still throws the error.
Body.Headers.ContentType = new MediaTypeHeaderValue("application/json;charset=UTF-8");
UPDATE: Content-Type is indeed an invalid header. The API Developers removed it at our request.
Try to set the property:
new MediaTypeHeaderValue("application/json")
{
CharSet = Encoding.UTF8.WebName
};
Try this one
HttpClient httpClient= new HttpClient();
httpClient.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "application/json; charset=utf-8");
Not sure if still relevant, but I recently ran into this same issue and was able to solve by setting the header in the following way:
string str = $"application/vnd.fmsstandard.com.Vehicles.v2.1+json; charset=UTF-8";
client.DefaultRequestHeaders.Add("Accept", str);
Try adding double quotes around UTF-8, like this:
Body.Headers.ContentType = new MediaTypeHeaderValue("application/json;charset=\"UTF-8\"");
EDIT:
Ok, try something like this. It's working for me locally with a WebApi I already had handy. Notice there is a header specification for what content-type will be ACCEPTED, and then there is a header for what content-type will be SENT with the request. For this example, both of them are JSON:
public static async Task<string> HttpClient(string url)
{
using(HttpClient client = new HttpClient())
{
client.BaseAddress = new Uri(url);
client.DefaultRequestHeaders
.Accept
.Add(new MediaTypeWithQualityHeaderValue("application/json")); // ACCEPT header
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, "");
request.Content = new StringContent("{\"id\" : 1}",
Encoding.UTF8,
"application/json"); // REQUEST header
HttpResponseMessage response = await client.SendAsync(request);
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
}
I only added the authentication header to it and it worked for me. AuthToken is either a string variable or the token itself. I left out the content type header and it just works. Below is the code; Response is a string that has to be serialized to a Jobject.
{
String Response = null;
HttpClient client = new HttpClient(CertByPass());
client.Timeout = TimeSpan.FromMinutes(5);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(AuthToken);
Response = await client.GetStringAsync(url);
}
Try creating a client helper class like:
HttpClient client = new HttpClient();
client.BaseAddress = new Uri(whatever your url);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
return client;
I am trying to setup a login via Oauth2 using EvE online's SSO system in .net core and am finding it impossible on the Post request stage. This is how I would have done it in the past with standard .net. Is anyone able to help me convert it over?
byte[] encodedKey = Encoding.UTF8.GetBytes(clientId + ":" + clientSecret);
//
HttpWebRequest request = HttpRequestHelper.CreateRequest(new Uri("https://login.eveonline.com/oauth/token"));
request.Host = Host;
request.Headers.Add("Authorization", "Basic " + encodedKey);
request.Method = "POST";
HttpRequestHelper.AddPostData(request, "grant_type=authorization_code&code=" + code);
string response = await requestAsync(request).ConfigureAwait(false);
var result = JsonConvert.DeserializeObject<AuthResponse>(response);
return result;
p.s. this is the post request format I am looking for
POST https://login.eveonline.com/oauth/token HTTP/1.1
Authorization: Basic bG9...ZXQ=
Content-Type: application/x-www-form-urlencoded
Host: login.eveonline.com
grant_type=authorization_code&code=gEyuYF_rf...ofM0
I wrote a module for EVEOnline SSO, in .net core 1.1 i'm using HttpClient to send the request
private readonly HttpClient _client;
public async Task<SsoResponse> AuthenticateAsync(string code)
{
if (string.IsNullOrEmpty(code))
throw new ArgumentNullException("Authentication code is null or empty");
// Build the link to the SSO we will be using.
var builder = new UriBuilder(_settings.BaseUrl)
{
Path = _settings.TokenPath,
Query = $"grant_type=authorization_code&code={code}"
};
var request = new HttpRequestMessage()
{
RequestUri = builder.Uri,
Method = HttpMethod.Post
};
// Set the necessary headers
request.Headers.Add("Authorization", $"{TokenType.Basic} {_authorizationString}");
request.Headers.Add("Host", builder.Host);
request.Headers.Add("User-Agent", _userAgent);
return await CallSsoAsync<SsoResponse>(request);
}
private async Task<T> CallSsoAsync<T>(HttpRequestMessage request)
{
T response = default(T);
using (HttpResponseMessage resp = await _client.SendAsync(request))
{
// Check whether the SSO answered with
// a positive HTTP Status Code
if (resp.IsSuccessStatusCode)
{
// Deserialize the object into the response model
// which will be returned to the application
response = JsonConvert.DeserializeObject<T>(await resp.Content.ReadAsStringAsync());
}
else
{
// Invalid code receieved, inform the user
throw new Exception("The SSO responded with a bad status code: " + resp.StatusCode);
}
}
return response;
}
Take a look at http://restsharp.org/. They also have a nuget package for .net core https://www.nuget.org/packages/RestSharp.NetCore/.
The usage is quite similiar to your example.
I am trying to a request a spotify access token using the procedure defined under 'Client Credentials Flow' on the Spotify developer page,
Here is my current implementation (Currently returns http 400 error):
using (var client = new HttpClient())
{
var requestBody = new StringContent(
"grant_type:client_credentials",
Encoding.UTF8,
"application/x-www-form-urlencoded");
var requestEncrypted = Convert.ToBase64String(
Encoding.UTF8.GetBytes(ClientId + ":" + ClientSecret));
client.DefaultRequestHeaders.Add(
"Authorization",
$"Basic {requestEncrypted}");
var tokenResult = await client.PostAsync(TokenEndpoint, requestBody);
}
I have tried other ways for formatting the request body including as json (Note: changing the encoding type to 'application/json' results in a http 415 error (media not supported)
For one, you need to use equals not a colon.
grant_type=client_credentials
Here is an example POST from the RFC.
POST /token HTTP/1.1
Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials
I'm new to Azure API management Rest Service. I created a new API Management, with a sharedaccesstoken.
using (HttpClient httpClient = new HttpClient())
{
var request = new HttpRequestMessage(HttpMethod.Post, requestUrl);
request.Headers.Authorization =
new AuthenticationHeaderValue("SharedAccessSignature", sharedAccessSignature);
request.Content = new StringContent("{\"accountEnabled\": true,\"creationType\": \"LocalAccount\",\"displayName\": \"Alex Wu\",\"passwordProfile\": {\"password\": \"Test1234\",\"forceChangePasswordNextLogin\": false},\"signInNames\": [{\"type\": \"userName\",\"value\": \"AlexW\"},{\"type\": \"emailAddress\",\"value\": \"AlexW#example.com\"}]}");
HttpResponseMessage response = await httpClient.SendAsync(request);
response.EnsureSuccessStatusCode();
responseBody = await response.Content.ReadAsStringAsync();
}
When i execute the code above i get a error:
{StatusCode: 405, ReasonPhrase: 'Method Not Allowed', Version: 1.1, Content: System.Net.Http.StreamContent, Headers:{ Date: Wed, 30 Mar 2016 19:38:15 GMT Content-Length: 73 Allow: GET Content-Type: application/json; charset=utf-8}}
Can someone help me moving forward so I will be able to create new users via the REST service.
I just read up on the API Reference specified in https://learn.microsoft.com/en-us/rest/api/apimanagement/user/createorupdate.
For starters, you should use HttpMethod.Put instead of Post. The request path should be base url + /users/{unique uid}. Also, from what I can tell, the attributes you are trying to pass are not available for this transaction.
If it's something else you're actually trying to accomplish then creating an Azure API Management User Entity, please advice and I'll try to guide you further.
Your answer helped me indeed. Below the implementation which made me accomplish my task.
string requestUrl = string.Format("{0}/users/{1}?api-version={2}", baseUrl, userGuid, apiVersion);
string responseBody = null;
try
{
using (HttpClient httpClient = new HttpClient())
{
var request = new HttpRequestMessage(HttpMethod.Put, requestUrl);
request.Headers.Authorization =
new AuthenticationHeaderValue("SharedAccessSignature", sharedAccessSignature);
request.Content = new StringContent("{\"firstName\": \"MyFirstName\",\"lastName\": \"MyLastName\",\"email\": \"example#mail\",\"password\": \"Password;\",\"state\": \"active\"}", Encoding.UTF8,"application/json");
HttpResponseMessage response = await httpClient.SendAsync(request);`enter code here`
response.EnsureSuccessStatusCode();
responseBody = await response.Content.ReadAsStringAsync();
}
}