Azure ACS get token using RestSharp 415 error - c#

The following is the code sample provided by msdn for obtaining an SWT token from azure ACS (Access Control Service):
private static string GetTokenFromACS(string scope)
{
string wrapPassword = pwd;
string wrapUsername = uid;
// request a token from ACS
WebClient client = new WebClient();
client.BaseAddress = string.Format(
"https://{0}.{1}", serviceNamespace, acsHostUrl);
NameValueCollection values = new NameValueCollection();
values.Add("wrap_name", wrapUsername);
values.Add("wrap_password", wrapPassword);
values.Add("wrap_scope", scope);
byte[] responseBytes = client.UploadValues("WRAPv0.9/", "POST", values);
string response = Encoding.UTF8.GetString(responseBytes);
Console.WriteLine("\nreceived token from ACS: {0}\n", response);
return HttpUtility.UrlDecode(
response
.Split('&')
.Single(value => value.StartsWith("wrap_access_token=", StringComparison.OrdinalIgnoreCase))
.Split('=')[1]);
}
I am trying to replicate the code using RestSharp:
var request = new RestRequest("WRAPv0.9", Method.POST);
request.AddHeader("Content-Type", "application/x-www-form-urlencoded");
request.AddParameter("wrap_name", uid, ParameterType.RequestBody);
request.AddParameter("wrap_password", pwd, ParameterType.RequestBody);
request.AddParameter("wrap_scope", realm, ParameterType.RequestBody);
RestClient client = new RestClient(
string.Format(#"https://{0}.{1}", serviceNamespace, acsHostUrl));
client.ExecuteAsync(request, Callback);
I tried other variations of the above code but to no avail. I keep recieving a 415 error stating that:
415 Unsupported Media Type T8000 Content-Type 'text/plain' is not
supported. The request content type must be
'application/x-www-form-urlencoded'.
I am not a Fiddler expert but with my limited experience with it I was not able to inspect my outgoing http request because it is encrypted.
I would appreciate advice on solving the issue.

You can try to leave out the AddHeader method call and instead set the Content-Type as the first AddParameter.
The issue is described here.

Related

NetSuite OAUTH1 POST request works in Postman but fails in Restsharp

I'm using RestSharp in .NET 6 to execute a POST request to NetSuite in a c# console application.
I'm using Token Based Authentication and OAuth1
When I execute the request using the same credentials (consumer key, consumer secret, access token, access token secret and realm) in C#, for GET requests, it works. I'm able to authenticate and get a response.
When I try a POST in C#, I get a 401, 'Unauthorized' with an error message stating that the token was rejected. The same POST request, with the same auth values and URL works in Postman however.
I feel like Postman is doing something to the authentication header in a different way to Restsharp, but that still doesn't explain why GET requests are working with RestSharp
public string ExecuteRequest(string url, int httpMethod, string body = "")
{
var client = new RestClient(url);
client.Authenticator = GetOAuth1Authenticator();
Method method = (Method)httpMethod;
var request = new RestRequest(url, method);
client.AddDefaultHeader("Accept", "*/*");
client.Options.MaxTimeout = -1;
request.AddHeader("Cookie", "NS_ROUTING_VERSION=LAGGING");
request.AddHeader("ContentType", "application/json");
if (string.IsNullOrEmpty(body) == false)
{
request.AddParameter("application/json", body, ParameterType.RequestBody);
}
var response = client.Execute(request);
if (response.IsSuccessful == false)
{
throw new HttpRequestException($"ERROR: {response.ErrorMessage} - RESPONSE CONTENT: {response.Content}");
}
if (response.Content == null)
{
throw new NullReferenceException("API RESPONSE IS NULL");
}
return response.Content;
}
private OAuth1Authenticator GetOAuth1Authenticator()
{
OAuth1Authenticator authenticator = OAuth1Authenticator.ForAccessToken(consumerKey: Credential.consumer_key,
consumerSecret: Credential.consumer_secret,
token: Credential.access_token, tokenSecret: Credential.access_token_secret, signatureMethod: RestSharp.Authenticators.OAuth.OAuthSignatureMethod.HmacSha256);
authenticator.Realm = Credential.accountId;
return authenticator;
}
For anyone who knows SuiteTalk REST API for NetSuite, I'm trying to do a POST request to transform a PO into a VendorBill, using this endpoint:
[netsuite host url]/purchaseOrder/{id}/!transform/vendorBill
try
var client = new RestClient(urlString);
var request = new RestRequest(Method.POST);
btw, check your oauth method, when you are generating the signature you must specify the method you are using ("POST")

Unsupported media type using RestSharp library

I start using RestSharp library to connect my Windows Forms application with web.
I created a method like this:
public static bool WebRequest(string route, string token, Method method, string model)
{
var client = new RestClient("myapiurl");
var request = new RestRequest(route, method);
//"model" is a json
request.AddParameter("application/json", model, ParameterType.GetOrPost);
request.AddHeader("Accept", "application/json");
request.AddHeader("Authorization", "Bearer " + token);
request.RequestFormat = DataFormat.Json;
IRestResponse response = client.Execute(request);
var content = response.Content;
return true;
}
The request has 3 parameters:
{ application/json={ "CommunicationType":4854,"JobNumber":55555,"NotificationAddress":"(714) 978-9788","CreatedBy":"user#mail.com","IsDeleted":false } }
{ Accept=application/json }
{ Authorization=Bearer dasjd... }
But the response always returns:
StatusCode: UnsupportedMediaType
I didn't see anything wrong in my request, can someone see what is wrong?
Regards
Add need to add content type in header
request.AddHeader("content-type", "application/json");
get reference GetOrPost:ParameterTypes for RestRequest
RequestBody If this parameter is set, its value will be sent as the
body of the request. Only one RequestBody parameter is accepted - the
first one.
The name of the parameter will be used as the Content-Type header for
the request.
RequestBody does not work on GET or HEAD Requests, as they do not
actually send a body.
If you have GetOrPost parameters as well, they will overwrite the
RequestBody - RestSharp will not combine them but it will instead
throw the RequestBody parameter away.
It is recommended to use AddJsonBody or AddXmlBody methods instead of
AddParameter with type BodyParameter. Those methods will set the
proper request type and do the serialization work for you.
I think you need to add
request.AddJsonBody(model); // AddJsonBody serializes the object automatically
In case anyone is encountering this, but for GET requests. I was encountering this same error and only saw answers saying a variation of the following solution to fix the Unsupported Media Type issue
request.AddHeader("content-type", "application/json");
For GET requests, you can also encounter this same error if you have the incorrect setting for Accept-Encoding. For my case, the API was only supporting gzip, so it was rejecting the default values that RestSharp was sending for Accept-Encoding header, which was gzip, deflate, br. The solution that worked for me was setting this Rest Client option:
var options = new RestClientOptions(url)
{
AutomaticDecompression = DecompressionMethods.GZip
};
_client = new RestClient(options);

OAuth2 Bearer Token not getting sent with RestSharp call

Credentials are right, because I can get an API response using PS with the same client id and secret. The token isn't invalid, but it won't get attached correctly to the rest request
Unauthorized. Access token is missing or invalid
Here's my code:
var client = new RestClient(url);
client.Authenticator = new OAuth2AuthorizationRequestHeaderAuthenticator("Bearer: " + OAuthToken);
var request = new RestRequest(Method.POST);
request.AddHeader("Content-Type", "application/x-www-form-urlencoded");
request.AddHeader("Accept", "application/json");
foreach (var paramName in parameters.Keys) {
request.AddParameter(paramName, parameters[paramName]);
}
request.RequestFormat = DataFormat.Json;
IRestResponse response = client.Execute(request);
if (response.StatusCode == HttpStatusCode.OK) {
string rawResponse = response.Content;
dynamic deserializedResponse = new JsonDeserializer().Deserialize<dynamic>(response);
return deserializedResponse;
}
else {
Dictionary<string, string> returnData = new JsonDeserializer().Deserialize<Dictionary<string, string>>(response);
throw new Exception("Failed call to API Management: " + string.Join(";", returnData));
}
I've also tried using:
request.AddHeader("authorization", "Bearer " + OAuthToken);
request.AddHeader("authorization", string.Format("Bearer " + OAuthToken));
request.AddHeader("authorization", string.Format("Bearer: " + OAuthToken));
request.AddHeader("authorization", $"Bearer {OAuthToken}");
request.AddParameter("authorization, "Bearer " + OAuthToken", HttpRequestHeader);
request.AddHeader("authorization", "bearer:" + access + "");
None worked.
Following code worked for me:
var restClient = new RestClient(Url)
{
Authenticator = new OAuth2AuthorizationRequestHeaderAuthenticator(accessToken, "Bearer")
};
As a result, the "Authorization" header will contain "Bearer {accessToken}"
I was not able to authenticate when I was using it like
request.AddHeader("Authorization", $"Bearer {axcessToken}");
instead this worked for me
client.AddDefaultHeader("Authorization", $"Bearer {axcessToken}");
You don't need the Authenticator.
First, you should decorate the controller or the action like below:
[Authorize(AuthenticationSchemes = "Bearer")]
public class ApiServiceController : Controller
{
}
or better than that:
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
public class ApiServiceController : Controller
{
}
Then you should add token bearer as this line:
request.AddParameter("Authorization", $"Bearer {OAuthToken}", ParameterType.HttpHeader);
where OAuthToken is the value of the received token from login.
If you need more codes, just tell me ;)
Question is old but for any one coming to this again.. this is what worked for me:
My project was configured to use Https, and I was not sending an Https request so server was sending me back a response informing that I should be using a Https request instead. After that, RestSharp performs automatically a redirect using Https this time, but is not including the Authorization Header. Mor infor here: https://github.com/restsharp/RestSharp/issues/414
My solutions was just to change my web api Url to use Https
https://.../api/values
Not sure if this will help anyone, but in my case the problem was JWT issue time. I was using current time, and the server was a few seconds behind. I noticed that the JWT token was working when I was stepping through the code, but not when I was running it without pausing. I fixed the problem by subtracting 1 minute from JWT issue time.
Use
var client = new RestClient(URL);
client.AddDefaultHeader("Authorization", string.Format("Bearer {0}", accessToken));
I had the same issue in ASP.NET Framework. Using the AddParameter, as below, worked.
RestClient client = new RestClient(Url);
RestRequest request = new RestRequest(Method.POST);
request.AddParameter("token", _OsiApiToken);
request.AddParameter("value", value);
IRestResponse response = client.Execute(request);
Prior to the above (working version) I had the Url as...
String.Format("https://myorg.locator.com/arcgis/rest/services/something/?token={0}&value={1}", X, Y)
Strangely the latter String.Format() worked in one project but not in another. Weird.

Microsoft Graph API: HttpStatusCode 200, Content-Length -1?

I'm trying to use Ms Graph API to connect to outlook and download attachment. What I have written till now is
private static async Task<HttpWebRequest> createHttpRequestWithToken(Uri uri)
{
HttpWebRequest newRequest = (HttpWebRequest)HttpWebRequest.Create(uri);
string clientId = "myClientId";
string clientSecret = "myClientSecret";
ClientCredential creds = new ClientCredential(clientId, clientSecret);
AuthenticationContext authContext = new AuthenticationContext("https://login.windows.net/myAzureAD/oauth2/token");
AuthenticationResult authResult = await authContext.AcquireTokenAsync("https://graph.microsoft.com/", creds);
newRequest.Headers.Add(HttpRequestHeader.Authorization, "Bearer " + authResult.AccessToken);
newRequest.ContentType = "application/json";
return newRequest;
}
And I'm using this to call the Graph APIs that I need. So to begin with, I tried calling this URL:
Uri uri = new Uri(("https://graph.microsoft.com/v1.0/users/myEmailId/messages"));
HttpWebRequest request = createHttpRequestWithToken(uri).Result;
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
After running the code, I get a response with HttpStatusCode 200 but the Content-Length is -1. I'm currently stuck here. Could someone please help me with where I'm going wrong / how to debug this piece of code further.
Thanks in advance.
The API uses "Transfer-Encoding: chunked" and hence Content-Length header is not returned. This is why you see default value of -1 for response.ContentLength property. To read the response body, simply read response stream obtained by response.GetResponseStream() method.

Docusign /oauth/token endpoint return page instead of json with bearer C#

I went through the OAuth2 proccess in DocuSign API, I follow all the steps using official docs, but when I tried to perform the request in order to get the the AccessToken I received an HTML as response, indicating something like "DocuSign is temporarily unavailable. Please try again momentarily." Although the http response is 200(OK), The weird stuff is when I test with the same values on Postman I get the correct response.
This is my code
public static DocuSignBearerToken GetBearerToken(string AccessCode, bool RefreshToken = false)
{
string AuthHeader = string.Format("{0}:{1}", DocuSignConfig.IntegratorKey, DocuSignConfig.SecretKey);
var client = new RestClient("http://account-d.docusign.com");
client.Authenticator = new HttpBasicAuthenticator(DocuSignConfig.IntegratorKey, DocuSignConfig.SecretKey);
var request = new RestRequest("/oauth/token", Method.POST);
request.AddHeader("content-type", "application/x-www-form-urlencoded");
request.AddHeader("authorization", "Basic " + Base64Encode(AuthHeader));
if(!RefreshToken)
request.AddParameter("application/x-www-form-urlencoded", string.Format("grant_type=authorization_code&code={0}", AccessCode), ParameterType.RequestBody);
else
request.AddParameter("application/x-www-form-urlencoded", string.Format("grant_type=refresh_token&refresh_token={0}", AccessCode), ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
var responseString = response.Content;
DocuSignBearerToken Result = JsonConvert.DeserializeObject<DocuSignBearerToken>(responseString);
return Result;
}
Ok, this is awkward, reading the DocuSign docs they never specify if the authorization URL is http or https I assumed it was http, postman is smart enough to determine http or https when performs the request, my code doesn't, simply changing the Authorization URL from http:// to https:// solves the error.
If your tests using Postman work, then there is a problem with your code.
We've all been there, including me!
In these cases, I send my request to requestb.in to see what I'm really sending to the server. You'll find something is different from what you're sending via Postman.

Categories