I am trying to pull details from Yahoo! Fantasy Sports API using OAuth2.0. I got the access_token to query using YQL. My code
using (var client = new System.Net.WebClient())
{
client.Headers.Add("Authorization", "Bearer " + response.access_token);
var query = "select%20*%20from%20fantasysports.games%20where%20game_key%3D'nfl'";
Response.Write(query);
var url = String.Format("https://query.yahooapis.com/v1/yql?q={0}&format=json&diagnostics=true&callback=", query);
output = client.DownloadString(url);
}
My response
{
"query": {
"count": 0,
"created": "2015-09-27T17:39:48Z",
"lang": "en-US",
"diagnostics": {
"publiclyCallable": "true",
"url": {
"execution-start-time": "4",
"execution-stop-time": "137",
"execution-time": "133",
"http-status-code": "401",
"http-status-message": "Authorization Required",
"content": "http://fantasysports.yahooapis.com/fantasy/v2/games;game_keys=nfl"
},
"user-time": "138",
"service-time": "133",
"build-version": "0.2.240"
},
"results": null
}
}
I am getting an Authorization Required status message.
I think it has got to do something with my request header. Can someone help me on understanding why my request is rejected here?
Yahoo! has two OAuth Authorization Flows
Two legged flow
Three legged flow
Yahoo notes,
Most of the Fantasy API data relies on 3-legged OAuth, as much of the
data is specific to a certain Yahoo! user. However, you can use
2-legged OAuth to request purely public data. 2-legged OAuth
effectively boils down to making a request without setting an access
token through the default PHP OAuth library, or effectively using your
consumer key/secret as the token.
So we should go for three-legged flow of OAuth authorization as exactly described in the Yahoo! documentation. At the end of the authorization flow, you will get a oauth_token and oauth_token_secret.
Yahoo have provided this code in C# (Link here).
public static string GetUserDataFromYahoo(string requestEndPoint, string token, string tokenSecret)
{
var data = String.Empty;
var uri = new Uri(requestEndPoint);
string url, param;
var oAuth = new OAuthBase();
var nonce = oAuth.GenerateNonce();
var timeStamp = oAuth.GenerateTimeStamp();
var signature = oAuth.GenerateSignature(
uri,
consumerKey,
consumerSecret,
token,
tokenSecret,
"GET",
timeStamp,
nonce,
OAuthBase.SignatureTypes.HMACSHA1,
out url,
out param);
data = String.Format("{0}?{1}&oauth_signature={2}", url, param, signature);
var requestParametersUrl = String.Format("{0}?{1}&oauth_signature={2}", url, param, signature);
var request = WebRequest.Create(requestParametersUrl);
using (var response = request.GetResponse())
using (Stream dataStream = response.GetResponseStream())
using (StreamReader reader = new StreamReader(dataStream))
{
data = reader.ReadToEnd();
}
return data;
}
This code uses this OAuthBase.cs class.
And when you use this code, you will get a
OST_OAUTH_SIGNATURE_INVALID_ERROR
That is because, OAuthBase.cs has a bug that's been noted here. To correct that you have to do this.
Line 199 (in NormalizeRequestParameters method) must change from:
sb.AppendFormat("{0}={1}", p.Name, p.Value);
to
sb.AppendFormat("{0}={1}", UrlEncode(p.Name), UrlEncode(p.Value));
Happy coding!
I suggest that you have not correctly received the access_token. This is why you get Authorization Required on the call to the server.
You need to check your code that gets the access_token
Related
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")
I have a chatbot using C# language using Bot Framework and I'm using the Luis api to recognize intent from the user input but I'm getting an error says: Unauthorized. Access token is missing, invalid, audience is incorrect (https://cognitiveservices.azure.com), or have expired
var GetRequest = new HttpClient();
var url = "?q=cars";
var MSG = new HttpRequestMessage(HttpMethod.Get, url);
MSG.Headers.Authorization = new AuthenticationHeaderValue("Ocp-Apim-Subscription-key", "");
var GetResult = GetRequest.SendAsync(MSG);
var res = GetResult.Result.Content.ReadAsStringAsync().Result;
await turnContext.SendActivityAsync(res);
In the url I'm putting the url to call the API and I'm adding the primary key to the headers.
When I test the API on postman its working perfectly and I get the response but in the code i got the error message.
Here is the response that I get when I test it in postman
"query": "cars",
"topScoringIntent": {
"intent": "Cars",
"score": 0.90734994
},
"entities": []
"Ocp-Apim-Subscription-key" is not the authorisation key, it's a simple header. There should probably be a BEARER token that you get from a login sequence.
MSG.Headers.Add("Ocp-Apim-Subscription-key", "<your subscription key>");
MSG.Headers.Authorization = new AuthenticationHeaderValue("BEARER", "<your bearer token>");
UPDATE: I figured it out and posted the answer below.
All I'm trying to do is update any file attribute. Description, name, anything, but no matter how I format it I get a 403.
I need to be able to modify a file so it can be shared via the Box API from a cloud app. I'm updating someone else's code from V1, but they are no longer available... I've tried many things but mostly just get 403 Forbidden errors.
There are no issues with OAuth2, that works fine and I can list files and folders, but can not modify them. This question is about sharing, but I can't change a description either. The box account is mine and I authenticate with my admin credentials. Any suggestions would be appreciated.
Here is the method I am using. I pass in the fileId and token and I've left out try/catch etc. for brevity.
string uri = string.Format("https://api.box.com/2.0/files/{0}", fileId);
string body = "{\"shared_link\": {\"access\": \"open\"}}";
byte[] postArray = Encoding.ASCII.GetBytes(body);
using (var client = new WebClient())
{
client.Headers.Add("Content-Type", "application/x-www-form-urlencoded");
client.Headers.Add("Authorization: Bearer " + token);
var response = client.UploadData(uri, postArray);
var responseString = Encoding.Default.GetString(response);
}
Thanks.
Okay, My Homer Simpson moment...
UploadData is a POST, I needed to do a PUT. Here is the solution.
string uri = String.Format(UriFiles, fileId);
string response = string.Empty;
string body = "{\"shared_link\": {\"access\": \"open\"}}";
byte[] postArray = Encoding.ASCII.GetBytes(body);
try
{
using (var client = new WebClient())
{
client.Headers.Add("Authorization: Bearer " + token);
client.Headers.Add("Content-Type", "application/json");
response = client.UploadString(uri, "PUT", body);
}
}
catch (Exception ex)
{
return null;
}
return response;
try changing your content type to 'multipart/form-data'?
I just looked up the api at: https://developers.box.com/docs/#files-upload-a-file
and it looks like the server is expecting a multipart post
here is stack overflow post on posting multipart data:
ASP.NET WebApi: how to perform a multipart post with file upload using WebApi HttpClient
I set up a developer acct under our shop, to access our sales receipts. I decided to use RestSharp to make my requests. I have proved it works for none Oauth required calls. I have successfully received my accessToken and accessTokenSecret. So i use those along with the customerKey and customerSecret to make a ForProtectedResource call, for a oauth request as follows but always receive "This method requires authentication".
I'm hoping its something simple I'm missing. I thought, all I need to make any call are those four items correct? Once I have those four items I don't have to request or access token anymore, correct? Thanks
var access_token = "#########################";
var access_token_secret = "########";
var baseUrl = "https://openapi.etsy.com/v2";
var client = new RestClient(baseUrl);
client.Authenticator = OAuth1Authenticator.ForProtectedResource(consumerKey,
consumerSecret,
access_token,
access_token_secret);
var request = new RestRequest("shops/########/receipts");
request.Method = Method.GET;
request.AddParameter("api_key", consumerKey);
client.ExecuteAsync(request, response =>
{
var r = response;
});
After some trial and error I finally wrapped my head around OAuth and the way Etsy implements it. The api_key parameter is only to be used when you're calling a none OAuth required method. Otherwise you have to send it all the required OAuth params. Below is working code. I leveraged RestSharp, as well as this OAuth base I found here. Hope this help some poor sap from staring at crappy code for 3 days (like yours truly).
var restClient = new RestClient(baseUrl);
OAuthBase oAuth = new OAuthBase();
string nonce = oAuth.GenerateNonce();
string timeStamp = oAuth.GenerateTimeStamp();
string normalizedUrl;
string normalizedRequestParameters;
string sig = oAuth.GenerateSignature(new Uri(baseUrl + MethodLocation), consumerKey, consumerSecret, Accesstoken, AccessTokenSecret, "GET", timeStamp, nonce, out normalizedUrl, out normalizedRequestParameters);
// sig = HttpUtility.UrlEncode(sig);
var request = new RestRequest(MethodLocation);
request.Resource = string.Format(MethodLocation);
request.Method = Method.GET;
// request.AddParameter("api_key", consumerKey);
request.AddParameter("oauth_consumer_key", consumerKey);
request.AddParameter("oauth_token", Accesstoken);
request.AddParameter("oauth_nonce", nonce);
request.AddParameter("oauth_timestamp", timeStamp);
request.AddParameter("oauth_signature_method", "HMAC-SHA1");
request.AddParameter("oauth_version", "1.0");
request.AddParameter("oauth_signature", sig);
restClient.ExecuteAsync(request, response =>
{
var r = response;
});
I'm trying to use RestSharp to access Etsy's API. Here's the code I'm using attempting to get an OAuth access token:
var authenticator = OAuth1Authenticator.ForRequestToken(
ConfigurationManager.AppSettings["ApiKey"],
ConfigurationManager.AppSettings["ApiSecret"]);
// same result with or without this next line:
// authenticator.ParameterHandling = OAuthParameterHandling.UrlOrPostParameters;
this.Client.Authenticator = authenticator;
var request = new RestRequest("oauth/request_token")
.AddParameter("scope", "listings_r");
var response = this.Client.Execute(request);
Etsy tells me that the signature is invalid. Interestingly enough, when I enter the timestamp and nonce values generated by the request into this OAuth signature validation tool, the signatures don't match. Moreover, the URL generated by the tool works with Etsy where the one generated by RestSharp doesn't. Is there something I'm doing wrong or something else I need to configure with RestSharp?
Note: I'm using the version of RestSharp provided by their Nuget package, which at the time of this posting is 102.5.
I finally was able to connect to the Etsy API with RestSharp using OAuth. Here is my code -- I hope it works for you...
RestClient mRestClient = new RestClient();
//mRestClient.BaseUrl = API_PRODUCTION_URL;
mRestClient.BaseUrl = API_SANDBOX_URL;
mRestClient.Authenticator = OAuth1Authenticator.ForRequestToken(API_KEY,
API_SHAREDSECRET,
"oob");
RestRequest request = new RestRequest("oauth/request_token", Method.POST);
request.AddParameter("scope",
"shops_rw transactions_r transactions_w listings_r listings_w listings_d");
RestResponse response = mRestClient.Execute(request);
if (response.StatusCode != System.Net.HttpStatusCode.OK)
return false;
NameValueCollection queryString = System.Web.HttpUtility.ParseQueryString(response.Content);
string oauth_token_secret = queryString["oauth_token_secret"];
string oauth_token = queryString["oauth_token"];
string url = queryString["login_url"];
System.Diagnostics.Process.Start(url);
// BREAKPOINT HERE
string oauth_token_verifier = String.Empty; // get from URL
request = new RestRequest("oauth/access_token");
mRestClient.Authenticator = OAuth1Authenticator.ForAccessToken(API_KEY,
API_SHAREDSECRET,
oauth_token,
oauth_token_secret,
oauth_token_verifier);
response = mRestClient.Execute(request);
if (response.StatusCode != System.Net.HttpStatusCode.OK)
return false;
queryString = System.Web.HttpUtility.ParseQueryString(response.Content);
string user_oauth_token = queryString["oauth_token"];
string user_oauth_token_secret = queryString["oauth_token_secret"];
The user_oauth_token and user_oauth_token_secret are the user's access token and access token secret -- these are valid for the user until the user revokes access.
I hope this code helps!