In the console, I follow up a call the site I'm on is is making and I can see the address (some.site.com/gettoken), message header and something that FF calls Message Body. It's in the latter that I can see the credentials that I've entered on the site that are being sent.
So, I've got the URL and the message body. Then, I've tried to implement the behavior using C# for my Azure service layer like so.
String url = #"https://some.site.com/gettoken";
String credentials = "username=super&password=secret";
using (WebClient client = new WebClient())
{
String output = client.UploadString(url, credentials);
result = output;
}
However, I get error 400 - bad result. What did I miss?
I've googled for some stuff but the only remotely relevant hits are talking about the upload methods, which I've used. Am I barking up the wrong tree entirely or just missing something tiny? Some people seem to get it to work but they're not tokenizing around. And I'm not certain enough to determine whether it's of relevance or not.
So, as a summary of what has been discussed in the comments: you can use the more modern HttpClient instead.
Note that this is the System.Net.Http.HttpClient and not Windows.Web.Http.HttpClient.
An example implementation could look like this:
public async Task<string> SendCredentials()
{
string url = #"https://some.site.com/gettoken";
string credentials = "username=super&password=secret";
using(var client = new HttpClient())
{
var response = await client.PostAsync(url, new StringContent(credentials));
return await response.Content.ReadAsStringAsync();
}
}
You might also be interested in System.Net.Http.FormUrlEncodedContent which allows you to pass in the parameters and their values so you don't have to construct the credentials value yourself.
More information on async/await.
Related
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!
I have my telegram application with app's api_id and app's api_hash.
I used TLSharp library for implementing my own things. But now I need to use this https://core.telegram.org/method/auth.checkPhone telegram api method, but it's not implemented in TLSharp library!
I don't mind doing it all manually, but I don't know how!
I know how you send post requests in C#, example:
var response = await client.PostAsync("http://www.example.com/index", content);
but in this specific case I don't. Because I don't know:
1) what link should I use for sending post requests? I couldn't find it on the telegram's website.
2) what content should I pass there? Should it be just "(auth.checkPhone "+380666454343")" or maybe the whole "(auth.checkPhone "+380666454343")=(auth.checkedPhonephone_registered:(boolFalse)phone_invited:(boolFalse))" ?
So, How do I sent this post request to the telegram api? (NOT telegram bot api!)
Try to use System.Net.Http like in this example (auth request to the server):
var user = new { login = "your login", password = "your pass" };
string json = JsonConvert.SerializeObject(user);
HttpContent content = new StringContent(json, Encoding.UTF8, "application/json");
HttpClient client = new HttpClient();
HttpRequestMessage request = new HttpRequestMessage();
request.RequestUri = new Uri("server route link"); // can be like https://a100.technovik.ru:1000/api/auth/authenticate
request.Method = HttpMethod.Post;
request.Content = content;
HttpResponseMessage response = await client.SendAsync(request);
responseText.Text = await response.Content.ReadAsStringAsync();
I think based on a brief look, that it would be more along the lines of your second example, e.g.:
var phonenumber = "0123456789";
var content =
$#"(auth.checkPhone ""{phonenumber}"")"+
"=(auth.checkedPhone phone_registered: (boolFalse) phone_invited:(boolFalse))";
var result = DoHttpPost("http://some.example.com/api/etc", content);
(note: I've not listed the actual mechanics of an HTTP Request here, as that is covered in plenty of detail elsewhere - not least in the other current answer supplied to you; DoHttpPost() is not a real method and exists here only as a placeholder for this process)
And since the payload of this appears to indicate the exact function and parameters required, that you'd just send it to the base api endpoint you use for everything, but I can't say for sure...
I do note they do appear to have links to source code for various apps on the site though, so perhaps you'd be better off looking there?
I'm receiving the following error while accessing the Microsoft Cognitive API:
I'm 100% sure that my subscription key is valid because I have tested it in DHC as well as the online tool of Project Oxford.
I'm using sample code provided by Microsoft. Here it is...
var client = new HttpClient();
var queryString = HttpUtility.ParseQueryString("safeee");
client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", "{bce8988422e94fd3ac64xxxxxxxxxxxx}");
var uri = "https://api.projectoxford.ai/face/v1.0/persongroups/{personGroupId}?" + queryString;
HttpResponseMessage response;
byte[] byteData = Encoding.UTF8.GetBytes("{body}");
using (var content = new ByteArrayContent(byteData))
{
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
response = await client.PutAsync(uri, content);
MessageBox.Show(response.ToString());
}
For any code snippet in the Microsoft Cognitive Services site, including the page to which I believe you're referring, you need to substitute all curly-braced strings with appropriate values. In your case, you need to:
Drop the query string "safeee" from the queryString. There are no query parameters for this particular endpoint.
Drop the curly braces in the Ocp-Apim-Subscription-Key value (sounds like you tried that.)
Give an approriate personGroupId value. Per the documentation on the aforementioned page, "valid characters include numbers, English letters in lower case, '-' and '_'. The maximum length of the personGroupId is 64."
Provide a proper JSON value for body. In your case you might simply use "{\"name\":\"safeee\"}".
I have been banging my head against the wall for the past 1 week now but without any success. Actually I'm writing a C# code(a web api controller action) to call another web api to make a post request with some json data payload in the request body. Syntax-wise there is nothing wrong with the code. But when I directly call the service(web api service) from web browser I get an Html form that has a multiline text box in it, rollback property (as radio button for true and false value for this property), drop down box with 2 options such as html and json (to get response in either format) and a button(for sending request to the server and making edits in the database). Now when I manually put json data inside text box and click the button on that html form edits are done successfully in the database but when programmatically(from my C# code) I send the same json data payload and make a post request edits are never done successfully rather I get an html response body through Fiddler that says status code success 200 but unable to complete operation,some parameters couldn't be recognized.
Here is my code
private static async Task<HttpResponseMessage> GeometryUpdateAsync(Feature updatedFeature, FeatureType featureType, int? objectid = null)
{
var jsonObject = new JObject();
dynamic esriId = jsonObject;
if (objectid == null)
{
objectid = updatedFeature.OBJECTID;
}
esriId.OBJECTID = objectid;
var mergedJsonString = JsonConvert.SerializeObject(new
{
geometry = JObject.Parse(updatedFeature.Geometry.ToString()),
attributes = JObject.Parse(esriId.ToString())
});
mergedJsonString = String.Format("[{0}]", mergedJsonString);
HttpResponseMessage response = null;
using (var client = new HttpClient())
{
//string arguments = "rollbackOnFailure=true&f=pjson&features=";
client.BaseAddress = new Uri("somebaseaddress");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.Timeout = TimeSpan.FromSeconds(500.00);
//response = await client.PostAsJsonAsync("someuri", arguments + mergedJsonString);
response = await client.PostAsync("someuri", mergedJsonString, new System.Net.Http.Formatting.JsonMediaTypeFormatter());
if (response.IsSuccessStatusCode)
{
var v = response.Content.ReadAsStringAsync().Result;
}
}
}
When I look at the request body (through fiddler while making a post request through Html form) request body looks like
features=%5B%7B%22geometry%22%3A%7B%22paths%22%3A%5B%5B%5B-91.3888577181506%2C39.703158271352621%5D%91.381838690201192%2C39.690323806398723%5D%2C%5B-91.383241723424632%2C39.689645139311914%5D%2C%5B-91.3849700567206%2C39.6888078408094%5D%2C%5B-91.3861256828518%2C39.688248198995353%5D%5D%5D%7D%2C%22attributes%22%3A%7B%22OBJECTID%22%3A21%7D%5D&gdbVersion=&rollbackOnFailure=true&f=pjson
and the request body for the post request made programmatically looks likes
"[{\"geometry\":{\"paths\":[[[-91.3888577181506,39.703158271352621],[-91.381838690201192,39.690323806398723],[-91.383241723424632,39.689645139311914],[-91.3849700567206,39.6888078408094],[-91.3861256828518,39.688248198995353]]]},\"attributes\":{\"OBJECTID\":21}}]"
Even I tried appending this
string arguments = "rollbackOnFailure=true&f=pjson&features=";
in my commented out code above (where I'm using PostAsJsonAsync) to make the request body look like as if it's coming from Html form. But no success, even I'm not sure whether the JSonFormatter takes this arguments string in to account or just leaves it while serializing/deserializing during the run time. And the post request body that I get after appending "arguments" string to Json string looks like this
"rollbackOnFailure=true&f=pjson&features=[{\"geometry\":{\"paths\":[[[-91.3877577181506,39.703158271352621],[-91.36047320856953,39.702616420911333],[-91.383241723424632,39.689645139311914],[-91.3849700567206,39.6888078408094],[-91.3861256828518,39.688248198995353]]]},\"attributes\":{\"OBJECTID\":21}}]"
But still no success, Now I'm totally running out of ideas as to how to call web api service from my C# code so that web api thinks it's coming from that Html form and end up successfully doing edits in the database programmatically. All suggestions and ideas will be highly appreciated.
The trick lies somewhere else, I was using HttpClient to simulate browser post request and get result in c#. But in this particular scenario HttpClient is of no use. I changed to HttpWebRequest after seeing a code at How to make a post call to a Web Api Action? from utlimate_programmer_BR and it did the trick, again HttpClient was a bad choice by me to get this particular thing done.
I'm trying to fix an issue with a legacy asp.net WebForms application written about 6 years ago. I'll try to explain and hope that someone can see a fix.
Our application supports what we call an "API". Really it's just a couple of pages intended to be displayed within the pages of our customers' websites. We also provice a sample application that shows how to use it.
The sample app has some form fields for the caller to provide values. When submitted, we create a string of HTML containing a elelement with the tag that
submit()'s the form on postgback.
Example:
...
form1.submit();
This method works successfully as long as the end user puts our domain in thier trusted sites. Otherwise the user gets permission denied errors. However, recently, we've had a couple customers refuse to add us to trusted sites and
want the issue fixed another way.
One approach I've tries is to use HttpClient.PostAsync() to do what the form/script above does but from the server side.
public HttpResponseMessage Post(string address, MediaTypeWithQualityHeaderValue acceptType, List<KeyValuePair<string, string>> data)
{
using (HttpClient client = new HttpClient())
{
//client.BaseAddress = new Uri(address);
client.DefaultRequestHeaders.Accept.Add(acceptType);
HttpContent content = new FormUrlEncodedContent(data);
HttpResponseMessage response = client.PostAsync(address, content).Result;
return response.EnsureSuccessStatusCode();
}
}
It's called like this:
string hash = GenerateHashValue();
List<KeyValuePair<string, string>> data = this.BuildPostData(hash);
MediaTypeWithQualityHeaderValue acceptType = new MediaTypeWithQualityHeaderValue("text/html");
HttpResponseMessage msg = Post(this.GetPostTargetUrl(), acceptType, data);
var task = msg.Content.ReadAsStringAsync();
task.Wait();
string result = task.Result;
Response.Write(result);
Response.End();
The response HTML is successfully written into the but it's essentally "disconnected" - nothing works after that. Normally, using the / method about uses can navigate in the iframe to other pages on our
site.Looking at it in fiddler, I see that some of the posts and redirects that I see when using the current / method is happeing and I get 404s for many of the javascript files coming from our site.
Can anyone suggest another approach in which I would not have XSS errors but a "connected" iframe?
Thanks,
Dan