Error 401 when tweets using node-twitter - javascript

I am using Twitter API by the package Twitter for Node.js.
Right now I succeed reading tweets using stream, but I failed to write tweets. I got 401 error which means Unauthorized according to Twitter Developer Documentation.
The code is here:
const Twitter = require('twitter');
const twitterClient = new Twitter({
consumer_key: TwitterConsumerKey,
consumer_secret: TwitterConsumerSecret,
access_token_key: TwitterAccessTokenKey,
access_token_secret: TwitterAccessTokenSecret
});
twitterClient.post('statuses/update', { status: 'Hello World!' }, (err, tweet, res) => {
if (err) throw err;
console.log(tweet);
console.log(res);
});
I did give write access. What could be other reasons causing this? Thanks

I made it work. Before I changed my access from "read" to "read, write, and direct messages". And I did regenerate my "consumer key and secret", also "access token and token secret" several times.
It should work, but it wasn't.
At last I totally delete the app on Twitter and recreated it, then it works!
Hope this can help people who met this weird issue.

Related

authentication conflict between sessions in Express server

I am playing around with this library and I am experiencing an annoying scenario which I believe comes from some sort of conflict in cookies or headers authentication.
When I login to one account everything works great. But then when trying to login to another account, it simply ignore the new data provided and move through the authentication with the old data and connecting to the old account. No matter if the email or the password even exist. (Tried also with fake data).
The library doesn't have proper logout method which make sense, you dont really need one because when you run it simply using node on your machine without any server involved and there is no cookies or any kind of data in memory, everything work great. I can login to as many account as I want.
The problem is when running it on an Express server.
CODE:
// api.js
const OKCupid = require("./okc_lib");
const Promise = require("bluebird");
const okc = Promise.promisifyAll(new OKCupid());
async function start(req, res, next) {
const {
body: {
username,
password
}
} = req;
try {
await okc.loginAsync(username, password);
okc.search(
searchOpt,
(err, resp, body) => {
if (err) return console.log({ err });
const results = body.data;
// do dsomething with results
return res.status(200).json({ message: "OK" });
});
}
);
} catch (error) {
res.status(400).json({ message: "Something went wrong", error });
}
}
module.exports = { start };
// routes.js
const express = require("express");
const router = express.Router();
const { start, login } = require("../actions/okc");
router.post("/login", login);
router.post("/start", start);
module.exports = router;
So when trying first to post to url/login it works fine. But when you try to do it again with different username and password it simply go through and ignore the new data and connect to the old one.
As part of my investigation I looked at the source code of the library and found a method clearOAuthToken which clear the token from the header. However it didn't really do anything. So I tried to remove the jar initialisation from the requester helper and it was the only thing that helped me to move on and login to another account. BUT it was only for experimenting and cant be a solution as you do need those cookies for other parts of the library. It was only a proof the problem isn't in the headers but in the cookies.
Any idea how can I "reset" state of server between each call?
"when trying to login to another account, it simply ignore the new data provided and move through the authentication with the old data and connecting to the old account."
As OP mentioned in the comment, this is not an authorization header issue, but a cookie issue.
To implement the logout interface, you can manually clear the cookies:
OKCupid.prototype.logout = function(){
request = request.defaults({jar: request.jar()}) // reset the cookie jar
headers.clearOAuthToken(); // just in case
}

Does third party authorized application have access to private tweet? i am having issue with user timeline REST API

I am not sure about whether third party authorized application have access to private tweet in twitter b/c i am getting error with {} (with status 200) when i used user timeline REST API.
I am using Twitter-npm.
//Initialise twitter client object-Twitter with keys
var client = new Twitter({
consumer_key: config.twitter.consumer_key,
consumer_secret: config.twitter.consumer_secret,
access_token_key: config.twitter.access_token_key,
access_token_secret: config.twitter.access_token_secret
});
client.get('statuses/user_timeline', tparam, function (error, tweets, response) {
if (error) {
console.log("error : " + JSON.stringify(error)); // error: {}
// i am getting error here {}
} else {
// data
}
});
It does not even get proper error message, so how can i get, why i am not getting tweets.
When i analysed i saw :
if the Protect your tweet is true in setting i am getting 200 with
error {}.
if the protect your tweet is false in setting i am getting 200 with
tweets.
i have also asked in twitter-community about this issue , but did not get fully response.
i also tried it using Postman , i get
{"request":"\/1.1\/statuses\/user_timeline.json","error":"Not authorized."}
and if any other error come it give error with code and message for example.
{"errors":[{"code":32,"message":"Could not authenticate you."}]}
why it's not giving such in my case?

instafeed.js stopped working: The access_token provided is invalid

I am using instafeed.js like so:
var feed = new Instafeed({
get: 'user',
userId: 19191919191,
limit: 9,
accessToken: 'myaccesstokenhere',
target: 'instagram',
resolution: 'standard_resolution',
after: function() {
var el = document.getElementById('instagram');
if (el.classList)
el.classList.add('show');
else
el.className += ' ' + 'show';
}
});
but I am getting this error:
The access_token provided is invalid.
I got the access_token by https://www.instagram.com/developer I registered my application and put the Client Secret as the accessToken and I got my userID from here https://smashballoon.com/instagram-feed/find-instagram-user-id/
but its still saying The access_token provided is invalid. what am I doing wrong?
You cannot use your Client Secret in place of accessToken, as the Client Secret is used server-side as part of the OAuth process in order to get the user accessToken.
I suggest reviewing Instagram's Authentication docs here to be sure you're using the Authentication strategy that makes sense for your application.
It sounds like you're more likely to want to use their Client Side Implicit Authentication (at the bottom) to get an access token. You can even do this yourself manually to just get an accessToken for testing. Once you have the accessToken, then you can simply use that in the correct field for instafeed.js to load what you want from Instagram.
You can also just get your own accessToken by going to http://instagram.pixelunion.net/ and using the one generated there.
Seems you confused accessToken with Client Secret, check it here https://www.instagram.com/developer/authentication/
To make life easy you can try to generate one here http://instagram.pixelunion.net/

ADAL JS - Acquire token: Token Renewal Operation failed due to timeout

I'm working in order to leverage the usage of the AD for authentication and authorization of several applications, and I'm currently studying how to implement said process.
This is for a Web-Browser to Web-Application flow.
I create an AuthenticationContext instance and use it to sign in, and that much functions normally.
(Code organization simplified for demo purposes)
this.adal = new AuthenticationContext({
tenant: this.tenantId,
clientId: this.clientId,
redirectUri: this.redirectUri,
callback: this.loginCallback,
popUp: true
});
this.adal.login();
It is when I try to acquire a Token that the behaviour becomes fishy.
It is relevant to say that this application's registry in the AD has the permission "Sign in and read user profile" on Microsoft Graph API.
this.adal.acquireToken("https://graph.microsoft.com", function(error, token) {
console.log(error);
console.log(token);
});
The error is written to the console as follows: "Token renewal operation failed due to timeout"; whilest token is written as a null object. A brief look at the "Network" tab while inspecting the page with Chrome reveals such a resource:
authorize?response_type=token&client_id=xxxxx&resource=xxxxx&redirect_uri=http://localhost:8080(.....)
The Status for said resource is 302.
Got any clues? Thanks!
Ok.. it seems like I've figured it out, with a little help from this article click for article and this click for very cool info
I've replaced the following bit of code, in the login callback
this.adal.acquireToken("https://graph.microsoft.com", function(error, token) {
console.log(error);
console.log(token);
});
for this:
var cachedToken = this.adal.getCachedToken(client_id_goes_here);
if (cachedToken) {
this.adal.acquireToken("https://graph.microsoft.com", function(error, token) {
console.log(error);
console.log(token);
});
}
And finally just add this line of code to a function that is run after the acquireToken method redirects to the page:
this.adal.handleWindowCallback();
Hope this is helpful for others who run by this issue!

Problems with OAuth on node.js

I am trying to get OAuth to work on node.js. I found this in the documentation of node-oauth:
var OAuth= require('oauth').OAuth;
var oa = new OAuth(requestUrl,accessUrl,consumerKey,consumerSecret,"1.0A",responseUrl,"HMAC-SHA1");
The next step in the official tutorial says:
"Then get hold of a valid access token + access token secret as per the normal channels"
What are these "normal channels"?
I know that the user has to authenticate somehow on the "vendor" site and that by some way a response url is called, but I can't find a description how to implement this. Can someone enlighten me?
I'm not sure what OAuth service you are trying to connect to so I'll just use twitter as an example. After you create your OAuth object you need to first request an oauth token. When you get that token, then you need to redirect to, for twitter, their authenticate page which either prompts them to login, then asks if it's ok for the app to login.
oa.getOAuthRequestToken(function(error, oauth_token, oauth_token_secret, results){
if (error) new Error(error.data)
else {
req.session.oauth.token = oauth_token
req.session.oauth.token_secret = oauth_token_secret
res.redirect('https://twitter.com/oauth/authenticate?oauth_token='+oauth_token)
}
});
When you first created the OAuth object, you set a responseURL, or the callback url. It can be anything, for my app its just /oauth/callback. In that callback you receive the oauth verifier token. You then use both the oauth request token and oauth verifier token to request the access tokens. When you receive the access tokens you will also receive anything else they pass, like their username.
app.get('/oauth/callback', function(req, res, next){
if (req.session.oauth) {
req.session.oauth.verifier = req.query.oauth_verifier
var oauth = req.session.oauth
oa.getOAuthAccessToken(oauth.token,oauth.token_secret,oauth.verifier,
function(error, oauth_access_token, oauth_access_token_secret, results){
if (error) new Error(error)
console.log(results.screen_name)
}
);
} else
next(new Error('No OAuth information stored in the session. How did you get here?'))
});
Hope this helps! I had the same problems when I started on this.
The access token is issued to your application after walking the user through the "OAuth dance" (as its affectionately known). This means obtaining a request token and redirecting the user to the provider (Twitter, in this case) for authorization. If the user grants authorization, Twitter redirects the user back to your application with a code that can be exchanged for an access token.
node-oauth can be used to manage this process, but a higher-level library will make it much easier. Passport (which I'm the author of), is one such library. In this case, check out the guide to Twitter authentication, which simplifies the OAuth dance down to a few lines of code.
After that, you can save the access token in your database, and use it to access protected resources in the usual manner using node-oauth.
An update to post tweet to user timeline:
#mattmcmanus, Extending #mattmcmanus nice answer, I would like to post a tweet to timeline. For this, I am using the same code as mattcmanus given above.
Step 1:
oa.getOAuthRequestToken(function(error, oauth_token, oauth_token_secret, results){
if (error) new Error(error.data)
else {
req.session.oauth.token = oauth_token
req.session.oauth.token_secret = oauth_token_secret
res.redirect('https://twitter.com/oauth/authenticate?oauth_token='+oauth_token)
}
});
Step 2:
app.get('/oauth/callback', function(req, res, next){
if (req.session.oauth) {
req.session.oauth.verifier = req.query.oauth_verifier
var oauth = req.session.oauth
oa.getOAuthAccessToken(oauth.token,oauth.token_secret,oauth.verifier,
function(error, oauth_access_token, oauth_access_token_secret, results){
if (error) new Error(error){
console.log(results.screen_name)
}else{
// NEW CODE TO POST TWEET TO TWITTER
oa.post(
"https://api.twitter.com/1.1/statuses/update.json",
oauth_access_token, oauth_access_token_secret,
{"status":"Need somebody to love me! I love OSIpage, http://www.osipage.com"},
function(error, data) {
if(error) console.log(error)
else console.log(data)
}
);
// POST TWEET CODE ENDS HERE
}
}
);
} else
next(new Error('No OAuth information stored in the session. How did you get here?'))
});
I have added oauth_access_token & oauth_access_token_secret in commented code. This will post a tweet update to user's timeline. Happy tweeting!!!

Categories