HttpClient with csrf_token response unauthorized error - c#

so able to do this manually using postman. Two steps involved , first do a Get with UserID/password. From the response get the csrf token attach the same in Another post method. No Authentication required in second call but just token with JSON payload returns the 200 response code.
Now tried these steps in C# and getting UnAuthorized error. Not sure if am attaching the token correct. below is the code.
var awdToken = await getAWDToken();
if (awdToken != null)
{
awdAddUser = await AddAWDUser(awdToken, userDetails);
}
private async Task<string> getAWDToken()
{
using (var client = new HttpClient())
{
string targetUri = string.Empty;
string userId = string.Empty;
string pass = string.Empty;
Dictionary<string, string> _awdConfigs;
_userSecurityWrok.CleintConfiguration.ClientAppConfigs.TryGetValue(string.Concat("AWD", "1"), out _awdConfigs);
if (_awdConfigs != null)
{
_awdConfigs.TryGetValue("AWDShortNameURL", out targetUri);
_awdConfigs.TryGetValue("UserName", out userId);
_awdConfigs.TryGetValue("Password", out pass);
}
client.BaseAddress = new Uri(targetUri);
var byteArray = new UTF8Encoding().GetBytes(userId + ":" + pass);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(byteArray));
client.DefaultRequestHeaders.ExpectContinue = false;
var response = await client.GetAsync(targetUri).ConfigureAwait(false);
IEnumerable<string> _tokens = response.Headers.GetValues("csrf_token");
var token = _tokens.FirstOrDefault();
var responseInfo = await response.Content.ReadAsStringAsync();
return token;
}
}
private async Task<UpdateResult> AddAWDUser(string awdToken, UserDetail userDetails)
{
UpdateResult userAddresult = new UpdateResult() { Success = false, Errors = new List<string>(), Messages = new List<string>() };
ClientDetails clientData = await _clientWork.GetClientDetails(userDetails.ClientId);
var awdPayLoad = await prepareAWDPayload(userDetails);
using (var handler = new HttpClientHandler { UseCookies = false })
using (var client = new HttpClient(handler))
{
string targetUri = string.Empty;
Dictionary<string, string> _awdConfigs;
_userSecurityWrok.CleintConfiguration.ClientAppConfigs.TryGetValue(string.Concat("AWD", "1"), out _awdConfigs);
if (_awdConfigs != null)
{
_awdConfigs.TryGetValue("AWDShortNameURL", out targetUri);
}
client.BaseAddress = new Uri(targetUri);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Add("csrf_token", awdToken);
client.DefaultRequestHeaders.Add("Cookie", "csrf_token=" + awdToken);
client.DefaultRequestHeaders.ExpectContinue = false;
var content = new StringContent(awdPayLoad, Encoding.UTF8, "application/json");
var response = await client.PostAsync(targetUri, content).ConfigureAwait(false);
var responseInfo = await response.Content.ReadAsStringAsync();
if (response.StatusCode == HttpStatusCode.OK)
{
userAddresult.Success = true;
}
else
{
userAddresult.Success = false;
userAddresult.Errors = new List<string> { "AWD returned error as " + response.StatusCode.ToString() };
}
}
return userAddresult;
}
Need to get this working... any idea?
attaching postman dump
POST /devapp/awdServer/awd/services/v1/users/ HTTP/1.1
Host: awdwaldn.nonprod.awdprocess.net:8443
csrf_token: L1HmyGPvEC4GvrOqBioL0Q..
Content-Type: application/json
User-Agent: PostmanRuntime/7.20.1
Accept: */*
Cache-Control: no-cache
Postman-Token: 594c3d97-de46-4fc3-9c2d-1b5f74278e60,8be8e538-267f-4544-b33a-211b2d479b3b
Host: ***** //removed host details
Accept-Encoding: gzip, deflate
Content-Length: 325
Cookie: BIGipServerawdwaldn-nonprod-web-8443-dev-web=454308362.16671.0000; JSESSIONID=8hl6G3gImEf4S71c8CFIzfMd.JVM1
Connection: keep-alive
cache-control: no-cache
{
"userId": "DST1234",
"alias": "DST1234",
"password": "TextAW1#",
"firstName": "chi",
"lastName": "chan",
"workSelect": "1",
"group": "WORK GROUP",
"countryCode": 1,
"earlyTime": "00:00:01",
"lateTime": "23:59:59",
"queue": "N",
"status": "A",
"workSelect": 1
}

I found it. its the cookies. We need to read the cookies from first response and attach it to second one. Issue resolved. thanks for your help.

Related

C# REST Api always return 401 status code when i am calling API by HttpClient

I am working with Nasdaq Fund Network Data Service first time. i am calling their one of the API where passing user id,pwd and access key but always getting 401 status code. i am not able to figure out what is wrong in my http call. please some one have a look at the code and tell me where i made the mistake for which i am getting 401 status code instead of right response.
here is my sample code where i could not share actual credentials and access key.
giving the code
string url = "sample url";
Uri u = new Uri(url);
string username = "test1";
string password = "test2";
string accessKey = "myaccesskey";
var payload = new Dictionary<string, string>
{
{"username", username},
{"password", password},
{ "accessKey", accessKey}
};
string strPayload = JsonConvert.SerializeObject(payload);
//HttpContent c = new StringContent(strPayload, Encoding.UTF8, "application/json");
HttpContent c = new StringContent(strPayload, Encoding.UTF8, "application/x-www-form-urlencoded");
var response = string.Empty;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11;
using (var client = new HttpClient())
{
HttpRequestMessage request = new HttpRequestMessage
{
Method = HttpMethod.Post,
RequestUri = u,
Content = c
};
var result = client.SendAsync(request).Result;
if (result.IsSuccessStatusCode)
{
response = result.StatusCode.ToString();
}
}
This Error i am getting
{StatusCode: 401, ReasonPhrase: 'Check Username/Password or Access
Key', Version: 1.1, Content: System.Net.Http.StreamContent, Headers: {
Pragma: no-cache X-Frame-Options: SAMEORIGIN Cache-Control:
no-cache Date: Wed, 10 Aug 2022 11:55:36 GMT Content-Length: 0
Expires: -1 }}
Try the following in order to extract the JWT token you receive as a response.
var url = "https://nfn.nasdaq.com/servicecall/tempsession";
var formDataDictionary = new Dictionary<string, string>
{
{ "username", "test1"},
{ "password", "test2"},
{ "accessKey", "myaccesskey"}
};
var formData = new FormUrlEncodedContent(formDataDictionary);
using (var client = new HttpClient())
{
var response = await client.PostAsync(url, formData);
response.EnsureSuccessStatusCode();
var result = await response.Content.ReadAsStringAsync();
var responseBody = JObject.Parse(result);
var accessToken = responseBody["data']"].Value<string>();
}

Creating an issue using JIRA Rest API returns HTTP status code 200 but the issue is not created

I want to create an issue with Jira Rest API using C#
string data = #"{ ""fields"": {
""project"":
{
""key"": ""TOTEM""
},
""summary"": ""just a test"",
""description"": ""Creating of an issue using project keys and issue type names using the REST API"",
""issuetype"": {
""name"": ""Task""
},
""assignee"": { ""name"": ""imane.elbarchi"" }
}
}";
//Console.WriteLine(data);
string uri = "https://proactioneu.ent.cgi.com/rest/api/latest/issue";
System.Net.Http.HttpClient client = new HttpClient();
//Putting URI in client base address.
client.BaseAddress = new Uri(uri);
//Putting the credentials as bytes.
byte[] cred = UTF8Encoding.UTF8.GetBytes("username:password");
//Putting credentials in Authorization headers.
client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", Convert.ToBase64String(cred));
//Putting content-type into the Header.
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
//I am using StringContent because I am creating console application, no any serialize I used for manipulate the string.
var content = new StringContent(data, Encoding.UTF8, "application/json");
System.Net.Http.HttpResponseMessage response = client.PostAsync("issue", content).Result;
Console.WriteLine(response);
Console.ReadKey();
}
}
}
and I get a response like:
StatusCode: 200, ReasonPhrase: 'Found', Version: 1.0, Content:
System.Net.Http.HttpConnection+HttpConnectionResponseContent, Headers:
{
Cache-Control: no-cache
Connection: close
Content-Type: text/html
}
but the issue is not created.
I think it is because of this line:
System.Net.Http.HttpResponseMessage response = client.PostAsync("issue", content).Result;
When I create an issue I use:
var response = await httpClient.PostAsync(httpClient.BaseAddress, content);
So the first parameter wants the url you want to send the content to. "issue" is not an url.
My code looks like this. Maybe you can use it.
public async Task<bool> PostIssueAsync(string userpass, string data)
{
HttpClient httpClient = new HttpClient();
httpClient.BaseAddress = new Uri(Constants.JiraUrl + "rest/api/latest/issue");
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", userpass);
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var content = new StringContent(data, Encoding.UTF8, "application/json");
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
try
{
var response = await httpClient.PostAsync(httpClient.BaseAddress, content);
return response.IsSuccessStatusCode;
}
catch (Exception ex)
{
Console.WriteLine(ex);
return false;
}
}

Forbidden access when calling twitter api geo/search.json

I'm new in using twitter API, I've successfully called:
https://api.twitter.com/1.1/statuses/user_timeline.json
api.twitter.com/1.1/followers/list.json
but when I call:
https://api.twitter.com/1.1/geo/search.json?query=Pakistan
I get Forbidden access.
Following is my request:
Method: GET, RequestUri: 'https://api.twitter.com/1.1/geo/search.json?query=Pakistan', Version: 1.1, Content: , Headers:
{
Authorization: Bearer xxxxxxxxxxxxxxxxxxxyyyyyyyyyyyyyyyzzzzzzzzzzzzzzzzzzzzzzzzz%aaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbb
}
And the response that I get is:
StatusCode: 403, ReasonPhrase: 'Forbidden', Version: 1.1, Content: System.Net.Http.StreamContent, Headers:
{
strict-transport-security: max-age=631138519
x-connection-hash: 3a7f405036803861a700cef30f7b1e7f
x-response-time: 107
Date: Fri, 05 May 2017 03:18:15 GMT
Set-Cookie: guest_id=v1%3A149395429589966721; Domain=.twitter.com; Path=/; Expires=Sun, 05-May-2019 03:18:15 UTC
Server: tsa_o
Content-Length: 91
Content-Type: application/json; charset=utf-8
}
If you're interested in looking at my C# code that I'm using, here you go:
public async Task<IEnumerable<string>> GetTweetsByLatLong(double latitude, double longitude, int count, string accessToken = null)
{
if (accessToken == null)
{
accessToken = await GetAccessToken();
}
var requestUserTimeline = new HttpRequestMessage(HttpMethod.Get, string.Format("https://api.twitter.com/1.1/geo/search.json?query=Pakistan"));
requestUserTimeline.Headers.Add("Authorization", "Bearer " + accessToken);
var httpClient = new HttpClient();
HttpResponseMessage responseUserTimeLine = await httpClient.SendAsync(requestUserTimeline);
if (responseUserTimeLine.IsSuccessStatusCode)
{
var serializer = new JavaScriptSerializer();
dynamic json = ((serializer.Deserialize<object>(await responseUserTimeLine.Content.ReadAsStringAsync())) as Dictionary<string, object>).Values.ElementAt(0);
//new System.Collections.Generic.Mscorlib_DictionaryValueCollectionDebugView<string, object>((json as Dictionary<string, object>).Values).Items[0]
var enumerableTwitts = (json as IEnumerable<dynamic>);
if (enumerableTwitts == null)
{
return null;
}
return enumerableTwitts.Select(t => (string)(t["name"].ToString()));
}
else
{
return new string[] { responseUserTimeLine.ToString() };
}
}
public async Task<string> GetAccessToken()
{
var httpClient = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Post, "https://api.twitter.com/oauth2/token ");
var customerInfo = Convert.ToBase64String(new UTF8Encoding().GetBytes(OAuthConsumerKey + ":" + OAuthConsumerSecret));
request.Headers.Add("Authorization", "Basic " + customerInfo);
request.Content = new StringContent("grant_type=client_credentials", Encoding.UTF8, "application/x-www-form-urlencoded");
HttpResponseMessage response = await httpClient.SendAsync(request);
string json = await response.Content.ReadAsStringAsync();
var serializer = new JavaScriptSerializer();
dynamic item = serializer.Deserialize<object>(json);
return item["access_token"];
}
I believe it is because you are using Application-only authentication by providing a Bearer token.
See "Requires Authentication" in both
https://dev.twitter.com/rest/reference/get/geo/search
and
https://dev.twitter.com/rest/reference/get/statuses/user_timeline
And read https://dev.twitter.com/oauth

Send httpcontent with PostAsync gives Internal Server Error

To send data as querystring in PostAsync Method, I am using following approach. but i am getting Inernal Server Error.
HttpResponseMessage response;
string stringContent = "{ 'request_key': 'ABCD1234', 'request_code': 'CODE', 'request_type':'ID_type' }";
using(var client = new HttpClient()) {
client.BaseAddress = new Uri(SubscriptionUtility.GetConfiguration("BaseURI"));
client.DefaultRequestHeaders.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(SubscriptionUtility.GetConfiguration("ContentType")));
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", SubscriptionUtility.GetConfiguration("BasicAuthentication"));
response = await client.PostAsync(SubscriptionUtility.GetConfiguration("SubscriptionAPI"), stringContent, new JsonMediaTypeFormatter());
if(response.IsSuccessStatusCode) {
var dataObjects = JsonConvert.DeserializeObject<List<TestClass>>(response.Content.ReadAsStringAsync().Result);
//foreach(var d in dataObjects) {
//}
}
}
But When i send the request through fiddler, Its working fine. Here is my fiddler request
User-Agent: Fiddler
Content-Type: application/json; charset=utf-8
Host: testapi.com
Content-Length: 93
Authorization: Basic 12fbe6e1f63d832aa33232323
Post Data:
{
"request_key":"ABCD1234",
"request_code":"CODE",
"request_type":"ID_type"
}
I have achieved the desire functionality using following approach
Post Request
using(var client = new HttpClient()) {
client.BaseAddress = new Uri(SubscriptionUtility.GetConfiguration("BaseURI"));
client.DefaultRequestHeaders.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(SubscriptionUtility.GetConfiguration("ContentType")));
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", SubscriptionUtility.GetConfiguration("BasicAuthentication"));
var values = new Dictionary<string, string>
{
{ "request_key", "ABCD1234" },
{ "request_code", "CODE" },
{ "request_type", "ID_type" }
};
var content = new FormUrlEncodedContent(values);
var response = await client.PostAsync(SubscriptionUtility.GetConfiguration("SubscriptionAPI"), content);
var responseString = await response.Content.ReadAsStringAsync();

HttpClient post request for WebApi using asp.net mvc application

I'm trying to consume WebApi but I'm having issues. My 'IsSuccessStatusCode' is always false and I have 404 in response.
I have tried multiple methods but can't be able to do it correctly.
Constants:
const string baseUri = ""; // base url of API
const string setDealFlagUri = "Deals/SetDealFlag";
Method 1, using PostAsync:
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(baseUri);
var content = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("deadId", "3"),
new KeyValuePair<string, string>("flagValueToSet", "true")
});
var response = await client.PostAsync(setDealFlagUri, content);
if (response.IsSuccessStatusCode)
{
return true;
}
}
Method 2, using PostAsJsonAsync:
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(baseUri);
DealFlag content = new DealFlag
{
deadId = 3,
flagValueToSet = true
};
var response = await client.PostAsJsonAsync(setDealFlagUri, content);
if (response.IsSuccessStatusCode)
{
return true;
}
}
WebApi request detail:
Curl:
curl -X POST --header 'Accept: application/json' '{baseApiurl}/Deals/SetDealFlag?dealId=3&flagValueToSet=true'
Request URL
{baseApiurl}/Deals/SetDealFlag?dealId=3&flagValueToSet=true
Response Body
{
"Successful": true,
"ErrorMessages": [],
"ValidationResults": {
"IsValid": false,
"ValidationErrors": []
}
}
Response Headers
{
"pragma": "no-cache",
"date": "Wed, 24 Aug 2016 18:38:01 GMT",
"content-encoding": "gzip",
"server": "Microsoft-IIS/8.0",
"x-aspnet-version": "4.0.30319",
"x-powered-by": "ASP.NET",
"vary": "Accept-Encoding",
"content-type": "application/json; charset=utf-8",
"cache-control": "no-cache",
"content-length": "198",
"expires": "-1"
}
Please help me to use this webapi function correctly.
Thanks!
I think that the problem is that your controller method has signature like
[HttpPost]
public HttpResponseMessage SetDealFlag(int dealId, bool flagValueToSet)
Am I right? If your answer is "Yes" so your method wants parameters in the URL.
And so you get 404 error becouse no one of yours Web API methods matches to that URL.
Send your parameters dealId and flagValueToSet in the URL is the solution.
I wrote simple console app for testing my theory and it works perfectly:
public static void Main(string[] args)
{
using (var client = new HttpClient())
{
try
{
// Next two lines are not required. You can comment or delete that lines without any regrets
const string baseUri = "{base-url}";
client.BaseAddress = new Uri(baseUri);
var content = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("deadId", "3"),
new KeyValuePair<string, string>("flagValueToSet", "true")
});
// response.Result.IsSuccessStatusCode == true and no errors
var response = client.PostAsync($"{baseUri}/Deals/SetDealFlag?dealId=3&flagValueToSet=true", null);
// response.Result.IsSuccessStatusCode == false and 404 error
// var response = client.PostAsync($"{baseUri}/Deals/SetDealFlag", content);
response.Wait();
if (response.Result.IsSuccessStatusCode)
{
return;
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
throw;
}
}
}

Categories