Xamarin Android with fitbit api- Add Authorization to header - c#

I have a xamarin android application that is connecting to fitbit through their API and xamarin.auth, I have the access token but am getting an unauthorized code when trying to GET the json response. I have tried to add the access token to the url but it did not work.
This is my code:
if (e.IsAuthenticated)
{
var request = new OAuth2Request("GET", new System.Uri("https://api.fitbit.com/1/user/-/profile.json?access_token=" + e.Account.Properties["access_token"]), null, e.Account);
request.AccessTokenParameterName = e.Account.Properties["access_token"];
string type = e.Account.Properties["token_type"];
var response = await request.GetResponseAsync();
var json = response.GetResponseText();
}
I can not figure out how to add the authorization to the header of the OAuth2Request.
Any help is much appreciated!

So I ended up adding a Custom Request class to extend the OAuth2Request class and added another GetResponseAsync function that takes the access token as a parameter. I then add the Authorization to the header and leave the rest of the function as is. Not sure if there's a way of doing this with Xamarin.Auth library the way it is, but it worked for me.
public class CustomRequest : OAuth2Request{ //..
public virtual async Task<Response> GetResponseAsync(string accessToken){//..
httpRequest.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);

Related

C# HttpClient cannot send authorization header to ASP.NET Core Web API

I am trying to use C# HttpClient from ASP.NET MVC to make a request to an API. My API is running on .NET 6.0.
httpClient.BaseAddress = new Uri(_url);
httpClient.DefaultRequestHeaders.Clear();
httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue($"Bearer", $"{token}");
var serialized = new StringContent(JsonConvert.SerializeObject(request), Encoding.UTF8, "application/json");
var httpResponseMessage = await httpClient.PutAsync(urlToSend, serialized);
Here is my code. I tried all the possibilities I saw on google. But when sending request, I can't send Authorization header.
I can send it with Postman.
Here is my API code:
[Consumes("application/json")]
[Produces("application/json", "text/plain")]
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(IResult))]
[ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(IResult))]
[HttpPut("changeuserpassword")]
public async Task<IActionResult> ChangeUserPassword([FromBody] ChangePasswordCommand changePasswordCommand)
{
var accessToken = Request.Headers[HeaderNames.Authorization];
return GetResponseOnlyResult(await Mediator.Send(changePasswordCommand));
}
Note: In my _url, I use http, not https.
I'm not sure but maybe the [AllowAnonymous]attribute remove the Authorization header from request just because it does not make sense if no authorization is needed.
Have you checked if the sent request contains the header using a tool like fiddler ?
I solved the problem by changing my base url from HTTP to HTTPS.
I tried with Fiddler and I got the same problem when I request to HTTP.
So thanks to #olivier-duhart .
To add to the accepted answer, the problem gets solved by changing from HTTP to HTTPS is due to the fact that, the Authorization header gets stripped during redirects.
This behavior is for security concerns and is by design, as mentioned in the github discussion here.
The same behavior may not be seen when using Postman vs HttpClient for example, is due to the way that different clients, have differing mechanisms, by which the subsequent requests (following a response status 30X) to the redirect location are handled.
Also a great answer elsewhere on stackoverflow : Authorization header is lost on redirect
Please review this link. Allow Anonymous will ignore the authentication header
https://github.com/dotnet/aspnetcore/issues/30546
I tried with the code. It seems working fine for me. Here is my code of console app
try
{
ChangePasswordCommand passobj = new ChangePasswordCommand() { password = "new password"};
string _url = "https://localhost:44395/api/Values/";
var httpClient = new HttpClient();
httpClient.BaseAddress = new Uri(_url);
httpClient.DefaultRequestHeaders.Clear();
httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue($"Bearer", $"MYTOKEN");
var serialized = new StringContent(JsonConvert.SerializeObject(passobj), Encoding.UTF8, "application/json");
var httpResponseMessage = await httpClient.PutAsync("changeuserpassword", serialized);
}
catch (Exception ex) {
}
And here is controler Api
[AllowAnonymous]
[Consumes("application/json")]
[Produces("application/json", "text/plain")]
[HttpPut("changeuserpassword")]
public async Task<IActionResult> ChangeUserPassword(ChangePasswordCommand changePasswordCommand)
{
var accessToken = Request.Headers[HeaderNames.Authorization];
return Ok();
}

Mimic Postman's Post API Request in C# .NET

I am trying to get Autherization Token for TD Ameritrade API using C# .NET. First I get a "CODE" following some steps. Then I use that code in Postman, send the request I get Authorization Code back.
Here is my C# .NET Code to do the same :- (the "CODE" is one time value, can't be re-use. I get a NEW CODE and use that in C# app)
public async Task SignIn(string consumerKey, string code, string redirectUrl = "https://127.0.0.1:4000/TDCallBack/SetCode?code")
{
var path = "https://api.tdameritrade.com/v1/oauth2/token";
using (var client = new HttpClient())
{
var dict = new Dictionary<string, string>
{
{ "grant_type", "authorization_code" },
{ "access_type", "offline" },
{ "client_id", $"{consumerKey}" },
{ "redirect_uri", redirectUrl },
{ "code", code }
};
var req = new HttpRequestMessage(HttpMethod.Post, path) { Content = new FormUrlEncodedContent(dict) };
var res = await client.SendAsync(req);
}
}
But I get "Invalid_Grant" as return, which means API call went to TD Ameritrate server but it did not return the Authorization Token. It could be header/data issue, but no explanation why it did not return an Authorization token.
I think it is a C# programming issue, because TD Ameritrade has a WEB Page (like swagger) to submit API Calls. Exact same API call work with same parameters/values (of course NEW CODE every time). Postman works, TD Ameritrade Website Works BUT my C# Code doesn't work. I will appreciate if I can get some light on this problem. Thanks.
Have you tried using a proxy (like Fiddler) to see what the differences are between the Postman request and request from your code?
That should go a long way towards finding obvious differences. It also looks like you’re not setting the content type to be x-www-form-urlencoded which may be necessary for the endpoint to properly handle the request.
See also: How to POST using HTTPclient content type = application/x-www-form-urlencoded

ASP.net MVC clients consume patch API get Bad request 400 returns

I'm using asp.net MVC 5 to consume API that also developed in asp.net MVC.
For POST and GET requests, I managed to make it work, except for PATCH that always get 400 bad request from web service.
This is what I do in my client controller:
using (HttpClient httpClient1 = new HttpClient())
{
string apiURLGetClientApproval = "/clients/approvals?action=" + actionType;
HttpMethod method = new HttpMethod("PATCH");
HttpRequestMessage message = new HttpRequestMessage(method, new Uri(baseAddress + apiURLGetClientApproval));
StringContent content = new StringContent(json, Encoding.UTF8, "application/json");
httpClient1.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("bearer", token.AccessToken);
message.Content = content;
var result = httpClient1.SendAsync(message).Result;
}
This is the content that I pass from my client to API:
{{"clients": [
{
"cn": "1132196",
"hitdate": "04/05/2021"
}]}}
PS :
I access API by postman and ajax from client side with this content, got success reponse.
I have tried with these solution, but same 400 error bad request responsed : PATCH Async requests with Windows.Web.Http.HttpClient class
This is how the parameter of API look like:
[CustomAuth(Roles = "Super Admin, Admin, User")]
[HttpPatch]
[Route("clients/approvals")]
public HttpResponseMessage UpdateClientApproval(HttpRequestMessage request, string action, [FromBody]JObject data)
{..... }
I have been dealing with the same exact problem for 2 days now. I just fixed it. I realised that sending a PATCH request probably required some specific payload [{"op":"replace"....}] as we can tell from using PostMan. However the PUT request doesn't, in fact most of the data on the business object would already be populated, so you modify what you want to change and send a PUT request instead. I just did that. I had to add the PUT action method in my controller and change the HttpClient to send a PUT request and it worked less than 5mins ago.

Google Drive API bad request from C# but fine from Postman

I'm using this request code from C# and getting a Bad Request result:
public class GoogleDriveManager
{
private static readonly HttpClient Client = new HttpClient();
private const string Access = "ACCESS";
public GoogleDriveManager()
{
Client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", Access);
}
public async Task<HttpResponseMessage> GetFilesAsync(string driveId)
{
var url =
$"https://www.googleapis.com/drive/v3/files?driveId={driveId}&includeItemsFromAllDrives=true&corpora=true&supportsAllDrives=true";
var result = await Client.GetAsync(url);
return result;
}
}
But when I make the same sort of request from Postman, it works great:
GET https://www.googleapis.com/drive/v3/files?driveId=DRIVEID&includeItemsFromAllDrives=true&corpora=drive&supportsAllDrives=true
(Authorization Bearer Token, with token value the same as the one used above)
What am I doing wrong on the C# side?
According to API documentation supported values for corpora are:
user
domain
drive
allDrives
Your Postman example has corpora=drive but your C# example shows corpora=true.

Setting up a REST Client Application (Post) from a Web API

I've been having a few issues in trying to retrieve the results of a POST operation from a Web Service.
I have been using a chrome extension to test the API Services and they are working there. However I've been having problems on implementing it in code.
This is an example of usage of the chrome extension:
What I'm trying to retrieve on code, is the last part, the json array that the POST operation generates, where it says accessToken.
However, in the code that I've been using below, I've only had access to the status (200 OK) etc.
Here's a preview of the code I am using:
{
HttpClient client = new HttpClient();
client.BaseAddress = new Uri(url.Text);
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(header.Text));
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, url.Text);
request.Content = new StringContent(body.Text, Encoding.UTF8, header.Text);
client.SendAsync(request)
.ContinueWith(responseTask =>
{
MessageBox.Show(responseTask.Result.Content.Headers.ToString());
}
);
}
The Header.Text is exactly "application/json", the body.Text is body which has those various properties such as username and password (in string format) and url.Text contains the complete URL to call the Web service.
I'd like to know what I'm doing wrong with my code, and what can I do to obtain that json array that contains the accessToken
In your code you need to use ReadAsStringAsync method to convert your HttpContent object to string/json. For example:
client.SendAsync(request)
.ContinueWith(responseTask =>
{
var jsonString = responseTask.Result.Content.ReadAsStringAsync().Result;
MessageBox.Show(jsonString);
});
then you can convert you jsonString as you need.

Categories

Resources