.NET API HttpRequestMessage not setting Header Authorization - c#

We have an front-end application that authenticates through a third party.
We also have an API with an endpoint that receives requests from this front-end application.
To validate the token sent from our front-end application (and issued by the third party), our API is grabbing the token in the Authorization Header of the request from our front-end application and setting it in the Authorization Header of a separate request we are making to that third party to validate the token (they have an endpoint specifically for this).
When we make the request in Postman, we get back a isValid: true response indicating that the token we provided was issued by them & is valid. However, if we make this same request from our API, we are getting a no token provided error (this is the same error we get in postman if we do not include a token in the authorization header of our request).
Here is the code:
public async Task<bool> IsValidTokenRequest(string token)
{
var request = new HttpRequestMessage(HttpMethod.Get, _config["ThirdParty:URI"] + "/api/security/token");
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
using var httpClient = new HttpClient();
var response = await httpClient.SendAsync(request);
response.EnsureSuccessStatusCode();
var isValidResponse = response.DeserializeResponseBody<IsValidTokenResponse>();
return isValidResponse.IsValid;
}
We have also tried setting the Headers like:
request.Headers.Add("Authorization", $"Bearer {token}");
request.Headers.Add("accept", "application/json");
When we put a breakpoint on the var response = await httpClient.SendAsync(request); line, we see the Authorization Headers are set in the 'request' object. However, we place our next breakpoint at the next line (response.EnsureSuccessStatusCode()), and the response.RequestMessage.Headers.Authorization is null.
Its like our API is clearing out the request headers when it makes the request? Does anyone have any idea how/why this could be happening?

Related

Any added headers to DefaultRequestHeaders will not make it through to the API

In my API project I have the following controller that works fine when called with Postman:
[HttpPost]
public async Task<ActionResult> Upload([FromHeader] string authorization, IFormFile payLoad) { ... }
When I use Postman, I add a string (Token) in the Auth section and specify the Type as Bearer Token. I then go to the Body section and set the Key payLoad as a File and choose a file to upload.
Postman generates C# - RestSharp code as follows:
var client = new RestClient("http://localhost:11764/api/logdata");
client.Timeout = -1;
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", "Bearer exampleTokenString");
request.AddFile("payLoad", "/C:/path/oqwi.zip");
IRestResponse response = client.Execute(request);
Console.WriteLine(response.Content);
I'm not using RestSharp so I haven't verified that the code above works but the Postman post itself within the tool works fine and my API gets all the data as I would expect.
In a separate client application, whenever I attempt to make a POST call, the API controller (at the top of this page) always receives null for the authorization parameter. The file loads in fine. Here is the client code trying to POST to the API with every example I attempted to add the header (I did not try them all at once):
Uri EndPoint = new Uri("http://localhost:11764/api/logdata");
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Authorization
= new AuthenticationHeaderValue("Bearer", AccessToken);
client.DefaultRequestHeaders.Add("Authorization", "Bearer " + AccessToken);
var request = new HttpRequestMessage(HttpMethod.Post, EndPoint)
{
Content = fileAsFormData
};
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", AccessToken);
request.Headers.Add("Authorization", "Bearer " + AccessToken);
var response = await client.SendAsync(request);
...
Note: The above is an example of every different attempt I made at adding the authorization and token; I didn't do all of the above at once.
I have inspected the object in the client during runtime and it appears as if the header(s) are added on where I would expect them to be. Using Fiddler, I can confirm this:
UPDATE: I've tried adding other headers, like CacheControl, and none of them make it through to the API. I see it on the client side during runtime, I see it in Fiddler, but then they're all scrubbed by the time they get to the API. I'm wondering if this Github discussion has anything to do with it:
https://github.com/dotnet/runtime/issues/26475
According to this Github ticket within the dotnet runtime team,
karelz commented on Oct 24, 2018 •
FYI: 2 weeks ago we released a security fix to remove Authorization request headers from redirects.
Thinking that redirects may be at the heart of the issue, by using Fiddler or the Visual Studio inspection tool, I was able to observe that the callback to my client was from https://localhost:5001. I was not expecting this...
When I was constructing the original client code to POST to my API, I was simply copying all of the values I had used when I was exercising these calls from Postman. As an example from Postman's C# RestSharp:
var client = new RestClient("http://localhost:11764/api/logdata");
This ultimately was a red herring caused by the intelligent way Postman handles redirects. Postman was indeed posting to http://localhost:11764 -- but then getting a secure redirect to https://localhost:5001. Postman would then subtly resend the original request with reattached headers to this new secure endpoint.
So after updating the endpoint that the client will POST to, from http://localhost:11764/api/logdata to https://localhost:5001/api/logdata, everything works as expected.
But why https://localhost:5001? It's setup this way in (most) launchSettings.json:
"MyProj.UploadApi.WebApi": {
"commandName": "Project",
"launchBrowser": false,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "https://localhost:5001;http://localhost:11764"
}

Asana API 403 Response in C#

I am trying to implement a Xamarin app that works with the Asana API.
I have successfully implemented the OAuth as documented in the Asana documentation here... at least I assume it is successful. I get an access token from the token endpoint in an HTTPResponse with HTTP Status "OK".
But then when I turn around and try to make an API call with that same access token, I get a 403 Forbidden error. I tried the same API call in my browser (after logging in to Asana), and it works fine, which leads me to believe that I do have access to the resource, I must have an issue with authorizing the request on my end.
The API call in question is (documented here): https://app.asana.com/api/1.0/workspaces.
My C# code is as follows (abbreviated to relevant parts, and assume that ACCESS_TOKEN contains the access token I got from the token exchange endpoint):
HttpClient client = new HttpClient();
client.BaseAddress = "https://app.asana.com/api/1.0";
client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", ACCESS_TOKEN);
client.DefaultRequestHeaders.Add("Accept", "application/json");
And then I use this HttpClient (named client) in the following function:
// Returns a list of the Asana workspace names for the logged in user.
private async Task<List<string>> GetWorkspacesAsync()
{
List<string> namesList = new List<string>();
// Send the HTTP Request and get a response.
this.UpdateToken(); // Refreshes the token if needed using the refresh token.
using (HttpResponseMessage response = await client.GetAsync("/workspaces"))
{
// Handle a bad (not ok) response.
if (response.StatusCode != HttpStatusCode.OK)
{
// !!!THIS KEEPS TRIGGERING WITH response.StatusCode AS 403 Forbidden!!!
// Set up a stream reader to read the response.
// This is for TESTING ONLY
using (StreamReader reader = new StreamReader(await response.Content.ReadAsStreamAsync()))
{
// Extract the json object from the response.
string content = reader.ReadToEnd();
Debug.WriteLine(content);
}
throw new HttpRequestException("Bad HTTP Response was returned.");
}
// If execution reaches this point, the Http Response returned with code OK.
// Set up a stream reader to read the response.
using (StreamReader reader = new StreamReader(await response.Content.ReadAsStreamAsync()))
{
// Extract the json object from the response.
string content = reader.ReadToEnd();
JsonValue responseJson = JsonValue.Parse(content);
foreach (JsonValue workspaceJson in responseJson["data"])
{
string workspaceName = workspaceJson["name"];
Debug.WriteLine("Workspace Name: " + workspaceName);
namesList.Add(workspaceName);
}
}
}
// I have other awaited interactions with app storage in here, hence the need for the function to be async.
return namesList;
}
Finally found the answer. It looks like I was using HttpClient incorrectly; a subtle thing that should be equivalent, but is not due to the way it is implemented.
The answer
I needed to place the final slash at the end of the BaseAddress property of HttpClient, and NOT at the start of the relative address for the specific request. This answered question explains this.
To fix my code
I needed to change the setting up of the BaseAddress:
HttpClient client = new HttpClient();
client.BaseAddress = "https://app.asana.com/api/1.0/"; // FINAL SLASH NEEDED HERE
And remove the slash from the request's relative address:
// DO NOT put slash before relative address "workspaces" here
using (HttpResponseMessage response = await client.GetAsync("workspaces"))
Why I got the original error
When HttpClient combined the BaseAddress with the relative URI I specified in GetAsync(), it dropped off some of the base address, since the final slash was not included. The resulting address from combining the BaseAddress with the relative URI was a valid URL, but not a valid page/API call in Asana. Asana thus did an automatic redirect to a login page, which, of course, the rest of the API call would be forbidden from there.
How I discovered this
In debugging, I grabbed the access token returned during my app's authorization with Asana. I then recreated the request to the "/workspaces" API myself in Postman, and the request worked as expected. This confirmed that my authorization worked fine, and the issue must be with the specific request rather than the authorization. In debugging I then looked into the HttpResponseMessage, which has a property called RequestMessage, that includes the actual URL the GetAsync() made the request against. I observed the Login URL from Asana, rather than the BaseAddress I specified... which led me to the question/
answer linked above.
Hope this explanation helps anyone who comes across a similar error!

How to request a microsoft azure resource using a access token? In short how can we use the generated access_token in azure?

I have registered an app in Azure. I can get access_token from oauth2/v2.0/token from password grant. I can also get refresh_token from oauth2/v2.0/token using refresh_token grant
But, How do I request a resource in Microsoft Azure using an access_token?
In short how can we use the generated access_token in azure?
When you would request anything on azure you have to pass your access
token as your request headerrequest.Headers.Authorization which is
Bearer token.
Here I am giving you an example how you could access azure resource using your access token.
//New Block For Accessing Data from Microsoft Graph Rest API
HttpClient _client = new HttpClient();
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, string.Format("https://graph.microsoft.com/v1.0/users"));
//Passing Token For this Request
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", "Pass Your Token Here");
HttpResponseMessage response = await _client.SendAsync(request);
//Get User List From Response
dynamic objGpraphUserList = JsonConvert.DeserializeObject<dynamic>(await response.Content.ReadAsStringAsync());
I am accessing Azure Active Directory User List using access token. I got this response
See the screenshot below:
Azure Resource API Access Sample :
As Per Gaurav Mantri's Recommendation I am also giving you another example how you could get azure resource group information. See below code snippet
//How You Would Request Microsft Resource Management API For Resources List
var azureSubcriptionId = "Your_Azure_Subcription_Id";
var resourceGroupName = "Your_Resource_Group_Name";
HttpClient _client = new HttpClient();
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, string.Format("https://management.azure.com/subscriptions/{0}/resourceGroups/{1}/resources?api-version=2019-10-01", azureSubcriptionId, resourceGroupName));
//Passing Token For this Request
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", "Pass Your Token Here");
HttpResponseMessage response = await _client.SendAsync(request);
//Get User List From Response
dynamic objAzureResourceGroupList = JsonConvert.DeserializeObject<dynamic>(await response.Content.ReadAsStringAsync());
Also Tested on PostMan.
For more details you could refer Official Docs
Hope this would help you.
This process has been defined very clearly here: https://learn.microsoft.com/en-us/rest/api/azure. Especially look at the section titled Create the request which will tell you exactly what needs to be done.

GET call to a Google API responds with "Unauthorized"

UPDATE: Figured this out. I DID need to add the authorization header as answered below but I also believe the issue for my particular use case is that the access token (which I verified through Postman) required more scopes to authenticate me fully, which makes sense since this API contains surveys that I am trying to access, which are also linked to a Google account. Once I added the extra scopes needed to access the surveys to the token request along with the authorization header code below I was able to connect successfully.
More info on adding scopes to C# code can be found here: http://www.oauthforaspnet.com/providers/google/
Hope this helps anyone running into similar issues. Thanks all!
I am trying to make a GET call to a Google API but it keeps responding with "Unauthorized" while I am logged in to Gmail. I've already implemented Google+ Sign-In in StartUp.Auth.cs and even saved the access token for later use.
So how do I get the HttpClient to authorize me?
I have an access token available but I do not know how to pass it in properly. I've seen examples with usernames and passwords, but I should not need to pass those parameters if I already have an access token? If anything, I should be able to have the user redirected to a login page instead if needed when I log out before running the solution.
What I am expecting when the project is run, is the result of the GET call to come back in the form of json but it always says I'm "Unauthorized" and I am probably missing 1 line of code somewhere...
Here is the code I am using:
using (HttpClient client = new HttpClient())
{
string _url = "https://www.googleapis.com/consumersurveys/v2/surveys?key={MY_API_KEY}";
client.BaseAddress = new Uri(_url);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
using (HttpResponseMessage response = client.GetAsync(_url).Result)
{
if (response.IsSuccessStatusCode)
{
using (HttpContent content = response.Content)
{
var Content = content.ReadAsStringAsync();
ViewBag.GoogleResponse = Content.ToString();
}
}
else
{
// THIS IS ALWAYS UNAUTHORIZED!
ViewBag.GoogleResponse = response.StatusCode + " - " + response.ReasonPhrase;
}
}
}
Please help with ideas or suggestions. Thanks!
You need to pass the auth token in an Authorization Header:
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
Have you ever gotten an response for this api/survey? If you were unable to get a response from the API by hitting it with Postman, you may have issues in the way you are targeting the API. The error being returned there seems like you weren't including the token in your request header. Did you click the Authorization tab below the request URL to add the OAuth token to your header? (Keep in mind that the {} characters need to be URL encoded)
Also, when you are referencing MY_API_KEY, is that analagous to your surveyId?
I don't have a lot of experience here, but I have a couple of suggestions :
1) I agree with Pedro, you definitely need to include the Authorization Header in your request.
2) If your MY_API_KEY is in fact the survey ID, you may be providing an incorrect URL (GoogleAPIs documentation indicates that it should be < http://www.googleapis.com/consumer-surveys/v2/surveys/surveyId >
Recommendation (after moving your API key to a string var named MY_API_KEY) :
string _url = "https://www.googleapis.com/consumersurveys/v2/surveys/";
client.BaseAddress = new Uri(_url);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", ViewBag.GoogleAccessToken);
using (HttpResponseMessage response = client.GetAsync(MY_API_KEY).Result)
{
if (response.IsSuccessStatusCode)
{
using (HttpContent content = response.Content)
{
var Content = content.ReadAsStringAsync();
ViewBag.GoogleResponse = Content.ToString();
}
}
Reference:
https://developers.google.com/consumer-surveys/v2/reference/
http://www.asp.net/web-api/overview/advanced/calling-a-web-api-from-a-net-client

HttpClient PostAsync to Blogger API

I am using the following API to allow me to interact with Google Blogger. I need to insert a post into the users blog. However I am having trouble with my PostAsync functionality. I get a 401 telling me that my request isn't authorized despite having an API Key, however I think I may not be properly inserting my OAuth token.
I have the following code,
This is the code where I set up my authorization header, (note the key there is fake but is the same form as what i think is the OAuth token)
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("ya29.AHES6ZTBZi1dWPVdlcF7qAD-nSM6XxwY2323232m4lXW");
And this is my PostAsync function
HttpResponseMessage response = await req.PostAsync(URLs.postBlogURL + blogID + URLs.postBlogURLPost, new StringContent(json));
Can anyone tell me where I am going wrong? Cheers.
[UPDATE]
I amen't sure whether the authorization has to include the string bearer in it.
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer ya29.AHES6ZTBZi1dWPVdlcF7qAD-nSM6XxwY2323232m4lXW");
This is how I was able to get the proper OAuth auth header set for my request:
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue( "Bearer", _accessTokenWrapper.Token.access_token );
The first parameter to the constructor is the scheme to use for the Authorization header. So in the request, the header reads:
Authorization: Bearer {the access token string}

Categories

Resources