I'm trying to get the followers for a user that has authenticated through my meteorjs app. I have used the {{loginButtons}} template and have found where the users tokens are. However I now have to create my authorized request by hand and I was hoping this'd be easy. But it's really hard and I feel like I'm wasting time with trying to figure out a way to create the oauth_signature..
Any help is welcome!
Supposing it is Twitter you're talking about I might be able to help you out.
I just managed to do the same thing as you want to do.
This nice piece of code provides a client to the Twitter API: https://github.com/mynetx/codebird-js
Personally I have placed it in the server-folder in my app to avoid exposure of keys etc.
As the codebird-js code take use of XMLHttpRequests and node.js do not come with such functionality by default - at least in a meteor.js context - you have to add the XHR-functionality yourself.
This NPM did it for me: https://npmjs.org/package/xmlhttprequest
However, as you can not deploy your meteor app with additional npm packages I found this solution How can I deploy node modules in a Meteor app on meteor.com? that suggests placing it in the public folder.
Finally I added those lines of code in the codebird-js just below the line that says
var Codebird = function () {
var require = __meteor_bootstrap__.require;
var path = require('path');
var fs = require('fs');
var base = path.resolve('.');
var isBundle = fs.existsSync(base + '/bundle');
var modulePath = base + (isBundle ? '/bundle/static' : '/public') + '/node_modules';
var XMLHttpRequest = require(modulePath + '/xmlhttprequest').XMLHttpRequest;
Finally you have to provide your tokens generated at dev.twitter.com and find your user's tokens stored in the Users collection.
EDIT:
Whenenver you have the above you make a new Codebird object: var bird = new Codebird();
Then you set tokens:
bird.setToken(USER_ACCESS_TOKEN, USER_ACCESS_TOKEN_SECRET);
And makes the call:
bird.__call('friends/ids', {
screen_name': SCREEN_NAME,
user_id: TWITTER_ID
},
function(reply){
console.log(reply);
});
Note that USER_ACCESS_TOKEN, USER_ACCESS_TOKEN_SECRET, USER_NAME & TWITTER_ID in the above example are placeholders. They are all found in the Meteor Users collection.
Related
The documentation for the new google hangouts chat says that you need to authorize the scope https://www.googleapis.com/auth/chat.bot to do pretty much anything.
Here's the error:
While generating an authentication URL using their OAuth2 client I get the message that the scope is invalid. I don't have that problem if I use https://www.googleapis.com/auth/chat or some other scope like the one for google plus.
When I try to google things on in the API Explorer no combination of the URL or parts of the URL work either.
Here is my code to fetch the URL, seems to work just fine for everything else:
var {google} = require('googleapis');
var OAuth2 = google.auth.OAuth2;
var oauth2Client = new OAuth2(
"clientid-idididid.apps.googleusercontent.com",
"_secretsuff",
"http://localhost:3000/auth/google/callback"
);
var scopes = [
"https://www.googleapis.com/auth/chat", //Works
"https://www.googleapis.com/auth/chat.bot" // Does not work
];
var url = oauth2Client.generateAuthUrl({
access_type: 'offline',
scope: scopes,
});
console.log(url);
In case others are running across this problem I think I've figured this out. Google doesn't seem need this auth scope enabled by a domain user because it's already authorised on the domain when your testing your bot. The "authorisation" of these scopes are dictated by users in a domain adding/removing bots from spaces.
I'll go into a bit of detail if you're confused.
When you create a bot in the console for an organisation https://console.cloud.google.com/apis/api/chat.googleapis.com/ your bot is added to the domain and can be added to spaces by users. If then go over to to the credentials and create a service account you can use that json file credentials to access the API as your bot. The code below gets a list of the people in a space.
var { google } = require('googleapis');
var chat = google.chat("v1");
var key = require('./google_service-account-credentials.json');
var jwtClient = new google.auth.JWT(
key.client_email,
null,
key.private_key,
['https://www.googleapis.com/auth/chat.bot'], // an array of auth scopes
null
);
jwtClient.authorize(function (err, tokens) {
chat.spaces.members.list({
auth: jwtClient,
parent: "spaces/AAAAD4xtKcE"
}, function (err, resp) {
console.log(resp.data);
});
});
If you try to get a list of members on other spaces (and other domains) the bot will fail with the exact same error message:
"Bot is not a member of the space."
I assume if you list your bot on the marketplace and it gets added to different domains and spaces google's API makes sure that your bot can do what it's trying to do on a space by space basis. It would be annoying have to setup some authentication flow after a bot has already been added for it to do its job. This is also probably why the current REST api doesn't let you list spaces under domains, it's not the paradigm this API works under.
It may have to do with one of the following:
The scope is created for service accounts. Make sure you are accessing the REST API with a service account.
Make sure that the bot is added to the room or space and has access to what you want it do.
Make sure the Service account is part of the bot project that you are using for the bot.
I am trying to make a trelloApp library for Google Apps Script which works fine when I run it as the owner of the script. Now when adding it as a library to a script of another user I always get an error message about using the wrong token.
This would be the library MXATH_jOrClwhJxK58e3b7OPNgVSik-PP
To test would be
var API_KEY = "Your Api Key"; //https://trello.com/1/appKey/generate
function test() {
var app = trelloApp.openById(API_KEY)
var organizations = app.getMyOrganizations();
for (var i = 0; i < organizations.length; i++) {
var organization = organizations[i];
Logger.log(organization.getId()+ ' ' + organization.getDisplayName())
}
}
This would be the library in itselve (I removed the script properties with the keys)
And the error I am getting is: Response truncated by the server: expired token (use the option muteHttpExceptions to view the complete repsonse completa) (line 50, archieve "")
The oauth1 depreceation for Google apps Script does not seem to matter as it works fine with my own user.
Nice looking library - just what I was looking for after much head-scratching about the Trello API!
I took a copy and found that if I deployed the authorization web app as "user running app" my copy of the library seemed to work fine from another Google Account.
I'm experimenting with Google Apps Script and Twitter, and I'd like to be able to access multiple Twitter accounts through one spreadsheet. At the moment I've attempted the approach below (a unique OAuthService name for each Twitter account), and this kind-of works but it clunky because I have to randomly authorize one account (and not more than one) each time the script is run, and the popup dialog doesn't tell me which account (i.e. id) I'm authenticating for.
Ideally, I'd like to force each user to give Twitter permission on first use, then store that token for later use - is this possible withe Google App Script?
Thanks.
function oAuth(id) {
var oauthConfig = UrlFetchApp.addOAuthService(NS_TWITTER + id);
oauthConfig.setAccessTokenUrl("https://api.twitter.com/oauth/access_token");
oauthConfig.setRequestTokenUrl("https://api.twitter.com/oauth/request_token");
oauthConfig.setAuthorizationUrl("https://api.twitter.com/oauth/authorize");
oauthConfig.setConsumerKey(CONSUMER_KEY);
oauthConfig.setConsumerSecret(CONSUMER_SECRET);
};
and then
var options =
{
"method": "GET",
"oAuthServiceName":NS_TWITTER + id,
"oAuthUseToken":"always",
};
try {
var result = UrlFetchApp.fetch(feed, options);
}
Yes, is possible.
To store the token values use userProperties (Docs here) or CacheService wich remains for 20 minutes in cache (Docs here).
Example storing token using UserProperties
UserProperties.setProperty('token', 'value');
var token = UserProperties.getProperty('token');
Example storing token using CachService
// Gets a cache that is private to the current user
var cache = CacheService.getPrivateCache();
cache.put('token', 'value');
var token = cache.get('token');
After building you cache solution you need to check if the token is valid with twitter API. If it's invalid you should require the auth again.
I'm trying to build a Google Apps Script that integrates with Trello, the idea being to use it to push information from spreadsheets and forms into the Trello API and create cards on a pending list on a certain board.
I found another question that pointed me in the right direction, and added in OAuth based on the GAS OAuth Documentation. The problem is I can't post the the board. I run the script, the OAuth prompt fires, and the script completes with no errors. I can also GET data from the private board, so I assume the authorization is working properly.
So, what am I doing wrong that prevents my script from POSTing to Trello?
Here's the code I'm working with:
var trelloKey = [Trello API key];
var trelloSecret = [Trello API key secret];
var trelloList = [the id of the list we're posting to];
var oauthConfig = UrlFetchApp.addOAuthService('trello');
oauthConfig.setAccessTokenUrl('https://trello.com/1/OAuthGetAccessToken');
oauthConfig.setRequestTokenUrl('https://trello.com/1/OAuthGetRequestToken');
oauthConfig.setAuthorizationUrl('https://trello.com/1/OAuthAuthorizeToken');
oauthConfig.setConsumerKey(trelloKey);
oauthConfig.setConsumerSecret(trelloSecret);
function createTrelloCard() {
//POST [/1/cards], Required permissions: write
var payload = {'name': 'apiUploadedCard',
'desc': 'description',
'pos': 'top',
'due': '',
'idList': trelloList};
var url = 'https://api.trello.com/1/cards'
var options = {'method' : 'post',
'payload' : payload,
'oAuthServiceName' : 'trello',
'oAuthUseToken' : 'always'};
UrlFetchApp.fetch(url, options);
}
You just need set fetch options contentType to application/json. I just resolved the same problem by this.
Try adding the scope=read,write in your authorization url.
from:
oauthConfig.setAuthorizationUrl('https://trello.com/1/OAuthAuthorizeToken');
to:
oauthConfig.setAuthorizationUrl("https://trello.com/1/OAuthAuthorizeToken?scope=read,write");
I have a Rails 3.2 application that uses Redis as it's session store. Now I'm about to write a part of new functionality in Node.js, and I want to be able to share session information between the two apps.
What I can do manually is read the _session_id cookie, and then read from a Redis key named rack:session:session_id, but this looks kind of like a hack-ish solution.
Is there a better way to share sessions between Node.js and Rails?
I have done this but it does require making your own forks of things
Firstly you need to make the session key the same name. That's the easiest job.
Next I created a fork of the redis-store gem and modified where the marshalling. I need to talk json on both sides because finding a ruby style marshal module for javascript is not easy. The file where I alter marshalling
I also needed to replace the session middleware portion of connect. The hash that is created is very specific and doesn't match the one rails creates. I will need to leave this to you to work out because there might be a nicer way. I could have forked connect but instead I extracted a copy of connect > middleware > session out and required my own in.
You'll notice how the original adds in a base variable which aren't present in the rails version. Plus you need to handle the case when rails has created a session instead of node, that is what the generateCookie function does.
/***** ORIGINAL *****/
// session hashing function
store.hash = function(req, base) {
return crypto
.createHmac('sha256', secret)
.update(base + fingerprint(req))
.digest('base64')
.replace(/=*$/, '');
};
// generates the new session
store.generate = function(req){
var base = utils.uid(24);
var sessionID = base + '.' + store.hash(req, base);
req.sessionID = sessionID;
req.session = new Session(req);
req.session.cookie = new Cookie(cookie);
};
/***** MODIFIED *****/
// session hashing function
store.hash = function(req, base) {
return crypto
.createHmac('sha1', secret)
.update(base)
.digest('base64')
.replace(/=*$/, '');
};
// generates the new session
store.generate = function(req){
var base = utils.uid(24);
var sessionID = store.hash(req, base);
req.sessionID = sessionID;
req.session = new Session(req);
req.session.cookie = new Cookie(cookie);
};
// generate a new cookie for a pre-existing session from rails without session.cookie
// it must not be a Cookie object (it breaks the merging of cookies)
store.generateCookie = function(sess){
newBlankCookie = new Cookie(cookie);
sess.cookie = newBlankCookie.toJSON();
};
//... at the end of the session.js file
// populate req.session
} else {
if ('undefined' == typeof sess.cookie) store.generateCookie(sess);
store.createSession(req, sess);
next();
}
I hope this works for you. It took me quite a bit of digging around to make them talk the same.
I found an issue as well with flash messages being stored in json. Hopefully you don't find that one. Flash messages have a special object structure that json blows away when serializing. When the flash message is restored from the session you might not have a proper flash object. I needed to patch for this too.
This may be completely unhelpful if you're not planning on using this, but all of my session experience with node is through using Connect. You could use the connect session middlewhere and change the key id:
http://www.senchalabs.org/connect/session.html#session
and use this module to use redis as your session store:
https://github.com/visionmedia/connect-redis
I've never setup something like what your describing though, there may be some necessary hacking.