I have OAuth set up with passport-twitter, and login and authentication is working fine. The problem comes when trying to do an authorized requests like updating status.
passport.use(new TwitterStrategy({
consumerKey: config.twitter.clientID
, consumerSecret: config.twitter.clientSecret
, callbackURL: config.twitter.callback_url || 'http://' + config.domain + '/auth/twitter/callback'
},
function(token, tokenSecret, profile, done) {
Player.findOne({ 'twitter.id': profile.id }, function (err, player) {
if (err) { return done(err) }
if (!player) {
var player = new Player({
name: profile.displayName
, twitter: profile._json
, twitter_token: token
, twitter_tokenSecret: tokenSecret
})
player.save(function (err, player) {
if (err) log.error(err);
return done(err, player);
})
}
else {
return done(err, player)
}
})
}
))
So this saves the Player via mongoose and works. I save the token and tokenSecret given by passport, and assume they have been generated with oAuth().getOAuthRequestToken()
as part of the original callback from Twitter, and so should be valid for the rest of the given login session. (maybe a bad assumption?)
Later, when we want to tweet something for the user, having fetched the Player record and its associated token+secret:
function twitter_oauth() {
return new OAuth (
"https://api.twitter.com/oauth/request_token",
"https://api.twitter.com/oauth/access_token",
keys.consumerKey,
keys.consumerSecret,
"1.0",
null,
"HMAC-SHA1"
)
}
....
twitter_oauth().post(api_endpoint, token, secret, body, "application/json",
function (error, data, res) {
if (error) {
console.error(error)
} else {
console.log('tweet sent')
}
}
)
The response to this is just status 401 and "Could not authenticate with OAuth."
So, am I missing something important? I have yet to dig into the passport source to find out what token
and tokenSecret
arguments actually are, but asking here hoping someone would point out the major flaw in the above.
Try to see if your application settings on dev.twitter.com are set to read & write.
Also check the timestamp in the header, if it's 5 minutes off to twitter's server clock the request will fail.
You could also try another library, I've used node-oauth or you could try ntwitter which is based on node-oauth.
thanks @Brmm for the good advice, but in this case it turns out we were using different twitter accounts in the keys for authentication and the api call, because, #bonehead
You can write this.
var tw = TwitterStrategy({
consumerKey: config.twitter.clientID
, consumerSecret: config.twitter.clientSecret
, callbackURL: config.twitter.callback_url || 'http://' + config.domain + '/auth/twitter/callback'
},
function(token, tokenSecret, profile, done) {
Player.findOne({ 'twitter.id': profile.id }, function (err, player) {
if (err) { return done(err) }
if (!player) {
var player = new Player({
name: profile.displayName
, twitter: profile._json
, twitter_token: token
, twitter_tokenSecret: tokenSecret
})
player.save(function (err, player) {
if (err) log.error(err);
return done(err, player);
})
}
else {
return done(err, player)
}
})
});
passport.use(tw);
and you don't need to new Oauth instance. you can use it like this.
tw._oauth.post(api_endpoint, token, secret, body, "application/json",
function (error, data, res) {
if (error) {
console.error(error)
} else {
console.log('tweet sent')
}
}
);
ciao!