Yammer API - Posting to External Networks - rest

I've used the Yammer API extensively for accessing current users internal network. All API calls have been working correctly (GET's and POST's) with the original token extracted from;
"https://www.yammer.com/oauth2/access_token.json?client_id={App ID}&client_secret={App Secret}&code={Access Code}"
and using the headers; "Authorization : Bearer {Token}" and "Cookie : {Cookies Received from HTML request}.
I've gotten the tokens for all accessible networks using;
"https://www.yammer.com/api/v1/oauth/tokens.json".
Accessing external networks beyond this point has proved troublesome. I changed the header to "Authorization : Bearer {NetworkToken}". While I am able to GET details from external networks, I cannot POST to external networks. I always receive a '401 Unauthorized' response. The 'Unauthorized' requests include deleting messages and liking messages in external networks.
Is there another step between being able to read data from an external network and enabling POST methods?
If I could get any insight into this i'd be extremely grateful!
Cheers!

When accessing external networks, you need to set the authToken to the authToken for that external network.
Step 1 - Get all auth tokens:
yam.platform.request({
url: "oauth/tokens.json",
type: 'GET',
success: function (msg) {
accessTokens = msg;
/....
},
error: function (msg) {
console.log(msg);
error(msg);
}
Step 2: Set the authToken to the correct external network
var currentToken = "";
$.each(accessTokens, function (i,val) {
if (val.network_permalink == $.cookie('networkPermalink')) {
currentToken = val;
}
});

While I was working on a project last month, I used the following way to post message.
The message has to be Byte encrypted in UTF-8 format.
Specify the content type as "application/x-www-form-urlencoded".
So, an example code would be:
HttpWebRequest a = (HttpWebRequest)WebRequest.Create(postUrl);
a.Headers.Add("Authorization", "Bearer" + authToken);
a.Method = "POST";
byte[] message = Encoding.UTF8.GetBytes("body=" + message + "&replied_to_id=" + threadID);
a.ContentType = "application/x-www-form-urlencoded";
a.ContentLength = message.Length;
using (var postStream = request.GetRequestStream())
{
postStream.Write(message, 0, message.Length);
}
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
using (var postStreamForResponse = response.GetResponseStream())
{
StreamReader postReader = new StreamReader(postStreamForResponse);
string results = postReader.ReadToEnd();
postReader.Close();
}

I've discovered quite a few inconsistencies quirks with the Yammer API. I've figured out external networks in their totality now. Here are some things that may not be clear;
When doing a POST or DELETE request, do not include the network_permalink in the url! Only include the network_permalink when you're doing a GET request. This was my main issue.
Required request headers;
Content-Type : application/x-www-form-urlencoded
Accept : application/json
Cookie : _workfeed_session_id=(A code that can be extracted from the response from your first request with an auth token)
Authorization : Bearer (Access token for whichever network you wish to access)
Oh and just FYI, to request threads within the 'All Company' group this is the url; https://www.yammer.com/(network_permalink)/api/v1/messages/general.json
Thanks for the answers!

Related

Payflow Gateway w/ Secure Token & Transparent Redirect - return URL issue

I've built a client (in .NET, but it could be in any framework) to consume the Payflow Gateway NVP API using the Transparent Redirect and Secure Token features. I am able to receive the token, send the credit card data, and receive an Approved response from PayPal. The problem is that PayPal is not redirecting properly back to my site. I passed a RETURNURL (http://localhost:49881/transaction/details?processor=PayflowGateway) parameter when requesting the Secure Token, but instead of returning me to that URL after the transaction, it navigates my browser to the following URL:
https://pilot-payflowlink.paypal.com/http%3A%2F%2Flocalhost%3A49881%2Ftransaction%2Fdetails%3Fprocessor%3DPayflowGateway?POSTFPSMSG=No%20Rules%20Triggered&RESPMSG=Approved&ACCT=1111&COUNTRY=US&PROCCVV2=M&VISACARDLEVEL=12&CVV2MATCH=Y&CARDTYPE=0&PNREF=A70A8EB8B6A1&AVSDATA=XXN&SECURETOKEN=9eGKZsSldEU6mIdSEV5DB4wWd&PREFPSMSG=No%20Rules%20Triggered&SHIPTOCOUNTRY=US&AMT=14.75&SECURETOKENID=1850a8f2-f180-4474-aa31-35d736fd7921&TRANSTIME=2016-03-24%2007:58:48&HOSTCODE=A&COUNTRYTOSHIP=US&RESULT=0&BILLTOCOUNTRY=US&AUTHCODE=872PNI&EXPDATE=1218
I have tried removing the "?processor=PayflowGateway" to fix the multiple question mark issue in the URL, but that doesn't seem to help. I've also tried tagging the RETURNURL[xx] with xx being the length of the URL value, but that seems to be the same as not passing a RETURNURL at all as it just shows a confirmation page on paypal.com instead of redirecting back to my site.
In PayPal Manager, I set the "Show confirmation page" setting to "On my website", Return URL to blank, and Return URL Method to GET. Are there any other settings or API request changes I need to make to get this to return properly to my test site?
This problem is caused because you're URL-Encoding the RETURNURL parameter passed when requesting the secure token from payflowpro gateway.
See the Do Not URL Encode Name-Value Parameter Data section on the Integration Guide.
Also, here you can get some C# code working you can use.
And some guidelines about PayPal HTTP here.
Do not use System.Net.Http.HttpClient nor System.Net.WebClient to make the HTTP POST to request the secure token. Instead use the low level System.Net.WebRequest to be able to write the POST data unencoded.
For example:
private string RequestSecureToken(double amount)
{
var secureTokenId = Guid.NewGuid().ToString();
var requestId = Guid.NewGuid().ToString();
var pairs = new Dictionary<string, string>()
{
{"PARTNER", "PayPal"},
{"VENDOR", "VENDOR NAME"},
{"USER", "USER NAME"},
{"PWD", "PASSWORD"},
{"TRXTYPE", "S"},
{"AMT", amount.ToString()},
{"CREATESECURETOKEN", "Y"},
{"SECURETOKENID", secureTokenId},
{"SILENTTRAN", "TRUE"},
{"RETURNURL", "http://mycompany.com/success"},
{"ERRORURL", "http://mycompany.com/error"}
};
string postData = string.Join("&", pairs.Select(p => string.Format("{0}[{2}]={1}", p.Key, p.Value, p.Value.Length)));
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("https://pilot-payflowpro.paypal.com");
request.Method = "POST";
request.ContentType = "text/namevalue";
request.Headers.Add("X-VPS-CLIENT-TIMEOUT", "45");
request.Headers.Add("X-VPS-REQUEST-ID", requestId);
request.ContentLength = postData.Length;
using (var writer = new StreamWriter(request.GetRequestStream()))
{
writer.Write(postData);
}
//Get the response
var response = request.GetResponse();
using (var reader = new StreamReader(response.GetResponseStream()))
{
return reader.ReadToEnd();
}
}

Azure encoding job via REST Fails

I am trying to upload a video and encode it via azure rest service.
I have now hit the step of encoding the video but I am having difficulties with the request.
The following code shows my request:
var joburl = res.RequestMessage.RequestUri + "Jobs";
client = new HttpClient();
client.DefaultRequestHeaders.TryAddWithoutValidation("Authorization", "Bearer " + token);
client.DefaultRequestHeaders.Add("x-ms-version", "2.8");
client.DefaultRequestHeaders.Add("DataServiceVersion", "3.0");
client.DefaultRequestHeaders.Add("MaxDataServiceVersion", "3.0");
client.DefaultRequestHeaders.Add("x-ms-date", date);
//accept
t = new NameValueHeaderValue("odata", "verbose");
type = new MediaTypeWithQualityHeaderValue("application/json");
type.Parameters.Add(t);
client.DefaultRequestHeaders.Accept.Add(type);
result = await client.PostAsync(joburl,json);
the url:https://wamsamsclus001rest-hs.cloudapp.net/api/Jobs
the json:
{"Name":"khgfiuydencodingjob","InputMediaAssets":[{"__metadata":{"Uri":"https://wamsamsclus001rest-hs.cloudapp.net/api/Assets('nb%3acid%3aUUID%3ad037b321-cd1c-43a9-9607-c4910fa7a85b')"}}],"Tasks":[{"Configuration":"H264 Adaptive Bitrate MP4 Set 720p","MediaProcessorId":"nb:mpid:UUID:1b1da727-93ae-4e46-a8a1-268828765609","TaskBody":"<?xml version=\"1.0\"encoding=\"utf-8\"?><taskBody><inputAsset>JobInputAsset(0)</inputAsset><outputAsset>JobOutputAsset(0)</outputAsset></taskBody>"}]}
The bearer token works as I use it for other request.
But I get a bad request 400 with the followin error message:
{"error":{"code":"","message":{"lang":"en-US","value":"Parsing request content failed due to: Make sure to only use property names that are defined by the type"}}}
Can anyone spot the error.
Thank you for the help
Okay I got it to work. Needed a odata=verbose in my json/string content - like this:
var jobInJson = JsonConvert.SerializeObject(job);
json = new StringContent(jobInJson, Encoding.UTF8);//,
json.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json;odata=verbose");
I tried this earlier however I got a error 500 but now it is working.

How to run Sharepoint Rest API from server side with elevated privileges?

The Sharepoint Rest API uses a simple URL of the type http://mysite/_api/search/query?querytext='search_key' to return search results as an XML. When I run this directly in a browser, I see a valid XML response:
(1) Am I right in assuming the above response is generated using the current user's authorization?
(2) Can this URL be invoked from server side? I tried it in a web method (WCF web service), but received a 401 - Unauthorized:
public string GetSearchResults(string searchKey)
{
string webURL = SPContext.Current.Web.Url;
string searchURL = webURL + "/_api/search/query?querytext='" + searchKey + "'";
WebClient client = new WebClient();
string xmlResponse = client.DownloadString(searchURL); // throws 401
// parse xmlResponse and return appropriately
}
(3) What I really need is to be able to get the search results irrespective of the current user's access rights (the requirement is that users will see all search results, with an option to "request access" when needed).
I tried this in the above web method, but it still throws the same 401:
public string GetSearchResults(string searchKey)
{
string webURL = SPContext.Current.Web.Url;
string searchURL = webURL + "/_api/search/query?querytext='" + searchKey + "'";
string xmlResponse;
SPSecurity.RunWithElevatedPrivileges(delegate()
{
WebClient client = new WebClient();
xmlResponse = client.DownloadString(searchURL); // still 401
});
// parse xmlResponse and return appropriately
}
What is the right way to invoke the Rest URL from server side? Specifically, from a web method? And how can it be run as super user?
In order to perform REST request, authenticate the request via WebClient.Credentials Property
On Premise (your scenario)
WebClient client = new WebClient();
client.Credentials = new NetworkCredential(userName,password,domain);
SharePoint Online
WebClient client = new WebClient();
client.Credentials = new SharePointOnlineCredentials(username,securedPassword);
client.Headers.Add("X-FORMS_BASED_AUTH_ACCEPTED", "f");
Search results are always security trimmed by SharePoint so to make this work, you'd need to run your query after specifying new credentials as mentioned by Vadim. This is almost certainly not a good idea. If you're running code server side already, don't use the REST interface, just query directly using the search API.

Handling CSRF/XSRF tokens with Angular frontend and Drupal 7 backend

I'm in the process of building a new AngularJS frontend for a Drupal 7 website. This is using the Services module with session-based authentication, across two domains using CORS. I am able to authenticate with Drupal, retrieve the user object and session data, and then get the CSRF token from the services module. What I'm having trouble with is setting all this up in the header so that subsequent requests are authenticated. I understand the overall concept but am new to both AngularJS and preventing CSRF attacks.
From what I have gathered reading about this set-up with AngularJS and RubyOnRails, there can be inconsistencies between platforms concerning what the token is named and how it is processed. There also seems to be a number of suggestions on how to set this token in the header. However, I'm having trouble in finding a solid example of how to get these platforms speaking the same language.
The only thing I'm doing with my $httpProvider in app.js is:
delete $httpProvider.defaults.headers.common['X-Requested-With'];
The login controller, in controller.js:
.controller('LoginCtrl', ['$scope', '$http', '$cookies', 'SessionService', function($scope, $http, $cookies, SessionService) {
$scope.login = function(user) {
//set login url and variables
var url = 'http://mywebsite.com/service/default/user/login.json';
var postDataString = 'name=' + encodeURIComponent(user.username) + '&pass=' + encodeURIComponent(user.password);
$http({
method: 'POST',
url: url,
data : postDataString,
headers: {'Content-Type': 'application/x-www-form-urlencoded'}
}).success(function (data, status, headers, config) {
var sessId = data.sessid;
var sessName = data.session_name;
$cookies[sessName] = sessId;
var xsrfUrl = 'http://mywebsite.com/services/session/token';
$http({
method: 'GET',
url: xsrfUrl
}).success(function (data, status, headers, config) {
$cookies["XSRF-TOKEN"] = data;
SessionService.setUserAuthenticated(true);
}).error(function (data, status, headers, config) {
console.log('error loading xsrf/csrf');
});
}).error(function (data, status, headers, config) {
if(data) {
console.log(data);
var msgText = data.join("\n");
alert(msgText);
} else {
alert('Unable to login');
}
});
};
The solution has to do with how the cookies need to be set and then passed through subsequent requests. Attempts to set them manually did not go well but the solution was simpler than I expected. Each $http call needs to set the options:
withCredentials: true
Another change I made was to use the term CSRF instead of XSRF, to be consistent with Drupal. I didn't use any built-in AngularJS CSRF functionality.
addItem: function(data)
{
return $http.post('api/programs/'+$stateParams.id+'/workouts', {item:data},{
headers:
{
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
'X-CSRF-Token': $('meta[name="xxtkn"]').attr('content')
}
});
}
since it has been a year of this topic! not sure still encountering the same problem but for the ones who comes to search for answers here is how i handle it!
Pay attention the headers{} part i define a new header and call it X-CSRF-Token and grab value from the DOM of (serverside) generated html or php. It is not a good practise to also request the csrf token from the server.Cuz attacker could somehow request that as well. Since you save it as a cookie. Attacker can steal the cookie! No need to save it in a cookie! send the token with header and read it in the serverside to match it!
and for multitab of a same page issue. I use the same token thruout the whole session.
Only regenerate on login, logout and change of major site or user settings.
There is a great library callse ng-drupal-7-services. If you use this in you project it solves authentication / reauthentication and file / node creation aut of the box and you can fokuse on the importent stuff in your project.
So Authentication is there solved like this:
function login(loginData) {
//UserResource ahndles all requeste of the services 3.x user resource.
return UserResource
.login(loginData)
.success(function (responseData, status, headers, config) {
setAuthenticationHeaders(responseData.token);
setLastConnectTime(Date.now());
setConnectionState((responseData.user.uid === 0)?false:true)
setCookies(responseData.sessid, responseData.session_name);
setCurrentUser(responseData.user);
AuthenticationChannel.pubLoginConfirmed(responseData);
})
.error(function (responseError, status, headers, config) {
AuthenticationChannel.pubLoginFailed(responseError);
});
};
(function() {
'use strict';
AuthenticationHttpInterceptor.$inject = [ '$injector'];
function AuthenticationHttpInterceptor($injector) {
var intercepter = {
request : doRequestCongiguration,
};
return intercepter;
function doRequestCongiguration (config) {
var tokenHeaders = null;
// Need to manually retrieve dependencies with $injector.invoke
// because Authentication depends on $http, which doesn't exist during the
// configuration phase (when we are setting up interceptors).
// Using $injector.invoke ensures that we are provided with the
// dependencies after they have been created.
$injector.invoke(['AuthenticationService', function (AuthenticationService) {
tokenHeaders = AuthenticationService.getAuthenticationHeaders();
}]);
//add headers_______________________
//add Authorisation and X-CSRF-TOKEN if given
if (tokenHeaders) {
angular.extend(config.headers, tokenHeaders);
}
//add flags_________________________________________________
//add withCredentials to every request
//needed because we send cookies in our request headers
config.withCredentials = true;
return config;
};
There is also some kind of kitchen sink for this project here: Drupal-API-Explorer
Yes, each platform has their own convention in naming their tokens.
Here is a small lib put together hoping to make it easy to use with different platforms. This will allow you to use set names and could be used across all requests. It also works for cross-domain requests.
https://github.com/pasupulaphani/angular-csrf-cross-domain

facebook Access Token 400 bad request

I am using following code to retrieve facebook accessToken
string url = "https://graph.facebook.com/oauth/access_token?" +
"client_id={0}" +
"&redirect_uri={1}" +
"&client_secret={2}" +
"&code={3}";
url = string.Format(url, clientId, redirectUri.EncodeUrl(), clientSecret, code);
//Create a webrequest to perform the request against the Uri
WebRequest request = WebRequest.Create(url);
try
{
//read out the response as a utf-8 encoding and parse out the access_token
using (WebResponse response = request.GetResponse())
{
using (Stream stream = response.GetResponseStream())
{
//string urlRedirects = response.ResponseUri.ToString();
Encoding encode = Encoding.GetEncoding("utf-8");
if (stream != null)
{
StreamReader streamReader = new StreamReader(stream, encode);
string accessToken = streamReader.ReadToEnd().Replace("access_token=", "");
streamReader.Close();
response.Close();
return accessToken;
}
}
}
}
catch
{
return null;
}
however I am constantly receiving this ambiguous error message
{
"error": {
"message": "Error validating verification code.",
"type": "OAuthException",
"code": 100
}
}
I checked the code 100 "Invalid parameter" doesn't means much to me at all.
anyone have had similar problem?
Check you are adding correct code in the url
For example
http://www.xyz.com/?code=AQC399oXame3UKmoAMYnqkZOEXPDNa8ZUFEY9sc6I4YNQnNT-ZgHzpMNnQVZrCUBZVqJRIB1QrXC5xW58_8MNIgQol_PaQvYssUM8OiKjSY5aoqGLBMuCeeHsSqP_mRTd1xiK0iretZcXwMm_27lFYrWFw345Mxod_lfJuB8zI13E8wJUQiArXW_ZlGLNcyxh20#_=_
Code must be
code = AQC399oXame3UKmoAMYnqkZOEXPDNa8ZUFEY9sc6I4YNQnNT-ZgHzpMNnQVZrCUBZVqJRIB1QrXC5xW58_8MNIgQol_PaQvYssUM8OiKjSY5aoqGLBMuCeeHsSqP_mRTd1xiK0iretZcXwMm_27lFYrWFw345Mxod_lfJuB8zI13E8wJUQiArXW_ZlGLNcyxh20
code should not include following in the end
#_=_
If above did not solve the problem
2. redirect_uri must end with /
redirect_uri=http://www.xyz.com/
The following gives some times above mentioned error
redirect_uri=http://www.xyz.com
3. A lso make sure
App on Facebook and Website with Facebook Login are set with same addresss
e.g http://www.xyz.com/
You need to send the user to the Facebook Login page to get a valid code. The code should then be used to get the access_token for the user.
Follow the Authentication Guide.
I also got error message 400, when my app id and secret were wrong (i had messed up develop and production id-s and secrets).
Fixing them (watch also out for the correct host) fixed this problem for me.