I am trying to get some information from an API using GetAsync, but I am getting a status code of 403 even after adding the OAuth authorization header with the token provided for me. Is there something else I need to do, or is my token bad?
class TestAPI
{
static void Main()
{
var client = new HttpClient();
client.BaseAddress = new Uri(BASE_ADDRESS_FOR_TESTING);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("OAuth", TOKEN);
HttpResponseMessage response = await client.GetAsync("WebApi/CaseLogs/v10/Search?DateFrom=04-05-2012");
if (response.IsSuccessStatusCode)
{
result = await response.Content.ReadAsStringAsync();
}
else
{
Console.WriteLine((int) response.StatusCode); // prints "403"
}
}
}
Your HttpClient looks fine to me. I think your Token is bad.
The 403 Error also supports this theory.
403
FORBIDDEN The server understood the
request but refuses to authorize it.
A server that wishes to make public why the request has been forbidden
can describe that reason in the response payload (if any).
https://httpstatuses.com/403
You should also print your response message.
using ( HttpResponseMessage response = await client.GetAsync("WebApi/CaseLogs/v10/Search?DateFrom=04-05-2012"))
using (HttpContent content = response.Content)
{
string result = await content.ReadAsStringAsync();
Console.WriteLine(result);
}
Try this code to see if you get more information in the response content.
Hope this helps.
Related
I'm trying to call a Tableau endpoint to get the list of project.
It is in 2 steps:
Call the signIn endpoint to get a token that allow to call others endpoint
Call the list projects endpoint with my signed In token
By using insomnia, this is working like a charm, but in csharp code, the first step is working well, but the second always returning me a 401 error.
Tableau list projects documentation
public async Task<string> ListProjectAsync()
{
var signIn = await SignInAsync(); // Working
var endPoint = $"https://myTableauSite.com/api/3.17/sites/{signIn.SiteId}/projects";
var acceptedCodes = new List<HttpStatusCode>();
acceptedCodes.Add(HttpStatusCode.OK);
var client = new HttpClient();
client.DefaultRequestHeaders.Add("X-Tableau-Auth", signIn.Token);
HttpResponseMessage response = await client.GetAsync(endPoint); // 401
response.EnsureSuccessStatusCode();
string responseString = await response.Content.ReadAsStringAsync();
return responseString;
}
Edit: The problem was from the JWT generated token that had a missing permission, my bad
The only difference I could find between your code's request and insomnia is that you forgot to set the content-type
public async Task<string> ListProjectAsync()
{
var signIn = await SignInAsync(); // Working
var endPoint = $"https://myTableauSite.com/api/3.17/sites/{signIn.SiteId}/projects";
var client = new HttpClient();
client.DefaultRequestHeaders.Add("Content-Type", "application/xml");
client.DefaultRequestHeaders.Add("X-Tableau-Auth", signIn.Token);
HttpResponseMessage response = await client.GetAsync(endPoint); // Should be working
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
It's a generic question, but I need help with my specific case.
I have a simple GET endpoint (see image) which I've tested with Postman and it works
It takes two id tokens in the header and thats it.
I've put breakpoints in the code and copied the exact instance of the ids into Postman and the request works, but executing from code, I get a 400 response
using (HttpClient client = new HttpClient())
{
var request = new HttpRequestMessage()
{
RequestUri = new Uri("https://*******.execute-api.ap-southeast-2.amazonaws.com/dev/uploads/image.jpg"),
Method = HttpMethod.Get,
};
var idToken = Application.Current.Properties["id_token"].ToString();
var accessToken = Application.Current.Properties["access_token"].ToString();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
request.Headers.Add("Id-Token", idToken);
request.Headers.Add("Access-Token", accessToken);
var response = await client.SendAsync(request);
}
I've tried with and without the content-type header and makes no difference. Also doesn't matter if it's present in Postman
This is a Xamarin project which is where Application.Current.Properties comes from. I'm utilising other endpoints in the application are there are no issues with accessing the tokens like this.
I'm trying to access/call methods in a REST API with a token from c#/.net- but I can't get any response back. I have googlet a lot - but without any success :-( I am new to call methods via a REST API.
I have an endpoint and a token which I need to use for communicating with a REST API. And I need to GET, POST, PUT and DELETE data on the server via those methods
The output from the API is in JSON format.
Maybe it is simple - but I don't know howto do it.
Any help is appreciated.
I have tried the following solution - but with no success :-(
private static async void DoIt()
{
using (var stringContent = new StringContent("{ \"firstName\": \"Andy\" }", System.Text.Encoding.UTF8, "application/json"))
using (var client = new HttpClient())
{
try
{
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", token);
// 1. Consume the POST command
var response = await client.PostAsync(endpoint, stringContent);
var result = await response.Content.ReadAsStringAsync();
//Console.WriteLine("Result from POST command: " + result);
// 2. Consume the GET command
response = await client.GetAsync(endpoint);
if (response.IsSuccessStatusCode)
{
var id = await response.Content.ReadAsStringAsync();
//Console.WriteLine("Result from GET command: " + result);
}
}
catch (Exception ex)
{
//Console.ForegroundColor = ConsoleColor.Red;
//Console.WriteLine(ex.Message);
//Console.ResetColor();
}
}
}
In your code you initialize AuthenticationHeaderValue with "Basic", which means Basic authentication based on username and password. If you have a token, you do it with:
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", ACCESS_TOKEN);
replace ACCESS_TOKEN with the token you have.
This is the most probable solution, but I can only guess here, as I don't know the API you're trying to access. If it still doesn't work, try ommiting "Bearer".
Reference
I have this code below code to create a database in couchDB:
private async void DatabaseCreate()
{
if (!await DatabaseExist())
{
var contents = new StringContent("", Encoding.UTF8, "text/plain");
this.uri = "http://USER:PASSWORD#localhost:5984/item_sn";
var response = await client.PutAsync(this.uri, contents); //set the contents to null but same response.
Console.WriteLine(response.Content.ReadAsStrifngAsync().Result);
}
}
My problem is that it is giving me a response with StatusCode:401, saying "Unauthorized". I tried curling it in the terminal and it gives me a successful response. Is there some preconditions I need to set for the httpclient? Or am I using the wrong method. I know there are some third party package for couchDB but for my case I just want to use C#'s httpclient.
Thanks in advance
curl command:
curl -X PUT http://USER:PASSWORD#localhost:5984/item_sn
Looks like in HttpClient class you can include credentials with HttpClientHandler Class with its Credentials property. Take a look at this answer. Try it, maybe that would work.
Here's the code that worked.
public async void DatabaseCreate()
{
if (!await DatabaseExist())
{
var contents = new StringContent("", Encoding.UTF8, "text/plain");
var byteArray = Encoding.ASCII.GetBytes("user:pass");
client.DefaultRequestHeaders.Add("Authorization", "Basic " + Convert.ToBase64String(byteArray));
this.uri = "http://localhost:5984/databasename";
var response = await client.PutAsync(this.uri, contents);
Console.WriteLine(response.Content.ReadAsStringAsync().Result);
}
}
I'm not sure, but it appears to me that the default implementation of .NET HttpClient library is flawed. It looks like it sets the Content-Type request value to "text/html" on a PostAsJsonAsync call. I've tried to reset the request value, but not sure if I'm doing this correctly. Any suggestions.
public async Task<string> SendPost(Model model)
{
var client = new HttpClient();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var response = await client.PostAsJsonAsync(Url + "api/foo/", model);
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
You should set the content type. With the Accept you define what you want as response.
http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
The Accept request-header field can be used to specify certain media types which are acceptable for the response. Accept headers can be used to indicate that the request is specifically limited to a small set of desired types, as in the case of a request for an in-line image.
public async Task<string> SendPost(Model model)
{
var client = new HttpClient(); //You should extract this and reuse the same instance multiple times.
var request = new HttpRequestMessage(HttpMethod.Post, Url + "api/foo");
using(var content = new StringContent(Serialize(model), Encoding.UTF8, "application/json"))
{
request.Content = content;
var response = await client.SendAsync(request).ConfigureAwait(false);
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync().ConfigureAwait(false);
}
}