Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use Twitter API from client side?

I'm trying to get information from twitter using angularjs and passport.

I've made the authentication through OAuth using passport js - it worked well - saved user information in a session.

Now I'm trying to run any GET command on twitter API with any endpoint (both V1.1 & V1) but it keeps complaining about authorization.

Example: executing in my controller

        $http.jsonp(https://api.twitter.com/1/statuses/user_timeline.json, {

        })

Gives me an error:

        GET https://api.twitter.com/1/statuses/user_timeline.json 401 (Unauthorized)

This command has worked in twitter console (and I use jsonp to avoid cross domain issues).

Should I pass any additional headers manually with this GET request - s.a auth_token etc?

Or why wouldn't it work? Should I exploit the fact that I've already made authentication to use the API? I've red https://dev.twitter.com/docs/auth/authorizing-request but didn't quiet understood.

Thanks For Helping,

like image 218
Igor Liphshon Avatar asked Apr 20 '14 14:04

Igor Liphshon


People also ask

Can I use Twitter API without authentication?

You can do application-only authentication using your apps consumer API keys, or by using a App only Access Token (Bearer Token). This means that the only requests you can make to a Twitter API must not require an authenticated user.

Can I still use Twitter API v1 1?

The v1. 1 search/tweets and the Twitter API v2 recent search endpoint support both OAuth 1.0a User Context and OAuth 2.0 App-Only. Therefore, if you were previously using the standard v1. 1 search endpoint you can continue using the same authentication method if you migrate to the Twitter API v2 version.


3 Answers

I recently implemented something similar using NodeJs (Passport) and AngularJs. If your implementation is somewhat similar you will need to authenticate the user in Twitter and request the user to authorize your application for access.

I am attaching snippets of the nodejs routing, the AngularJs interceptor and AngularJS routing to make this possible in my implementation. The passport and strategy is well documented in Passport so I am leaving it out of this solution to keep it short. My full implementation which is experimental is found in https://github.com/oredi/TwitThruSeet/ with in the following subfolders:

  • NodeJs routing - server/routes/routes.js
  • Passport strategy - server/lib/service/passport/twitterStrategy.js
  • AngularJs routing - webclient/js/app.js
  • AngularJs interceptor - webclient/js/interceptors.js

In nodejs you will need to create a middleware to authenticate your request as show in

app.get('/api/twitter/timeline', isLoggedIn, function (req, res) {
    getTwitterTimeLine(req, function (err, data, response) {
        if(err) {
            res.send(err, 500);
            return;
        }
        res.send(data);
    });
});

The route uses this middleware for authentication to check if the user has been logged in to Twitter and authorized your app.

// route middleware to make sure a user is logged in
function isLoggedIn(req, res, next) {
    if (!req.isAuthenticated())
        res.send(401);
    else
        next();
}

If the request is authorized then you make the call with the token and secret

function getTwitterTimeLine(req, callback) {
    var uri = 'https://api.twitter.com/1.1/statuses/home_timeline.json?count=';
    if(req.query.count) {
        uri += req.query.count;
    } else {
        uri += "10";
    }

    console.log(uri);
    passport._strategies.twitter._oauth._performSecureRequest(
        req.user.twitter_token,
        req.user.twitter_token_secret,
        'GET',
        uri,
        null,
        null, null, function (err, data, response) {
            var processedData;
            if(!err) {
                result = [];
                var max_id, since_id;
                var jsonData = JSON.parse(data);
                for (var i = 0; i < jsonData.length; i++) {
                    var record = jsonData[i];
                    var place_full_name = null;
                    if(record.place != undefined)
                        place_full_name = record.place.full_name;
                    result.push({
                        id_str: record.id_str,
                        created_at: record.created_at,
                        text: record.text,
                        user_screen_name: record.user.screen_name,
                        user_name: record.user.name,
                        user_profile_image_url: record.user.profile_image_url,
                        place_full_name: place_full_name
                    });
                }
            }
            callback(err, result, response);
        });
}

This is the route to get passport to authenticate with Twitter

app.get('/auth/twitter', passport.authenticate('twitter'));

You will need the following strategy for Passport if you are using my implementation to store the token and secret in req.user

var TwitterStrategy  = require('passport-twitter').Strategy;
module.exports.strategy = function(options) {
    return new TwitterStrategy({
        consumerKey: options.consumerKey,
        consumerSecret: options.consumerSecret,
        callbackURL: options.callbackURL
    },
    function(token, tokenSecret, profile, done) {
        // asynchronous verification, for effect...
        process.nextTick(function () {
            profile.twitter_token = token;
            profile.twitter_token_secret = tokenSecret;
            return done(null, profile);
        });
    });}

In your AngularJS module where the routing is configured, you will need to add an inteceptor to catch authentication events and reroute the user to Twitter's authorization page

angular.module('demoApi', ['demoApiSeet.interceptors', 'ngRoute'])
    .config(['twitterInterceptorProvider', '$routeProvider', '$locationProvider'
        ,'$httpProvider', function (twitterInterceptorProvider, $routeProvider,
            $locationProvider, $httpProvider) {
                twitterInterceptorProvider.RedirectUrl('/auth/twitter');
                $httpProvider.interceptors.push('twitterInterceptor');
}]);

Finally you need to have an interceptor that captures 401 requests and reroute to the Twitter auth endpoint detailed by your nodejs routing. Please take note that I implemented $window.location.href = authUrl; as I need the page to route to the Twitter auth endpoint during page api call or page on load. If the authentication is triggered manually this might not be required.

angular.module('demoApiSeet.interceptors', [])
    .provider('twitterInterceptor', function() {
        var redirectUrl;
        this.RedirectUrl = function(value) {
            redirectUrl = value;
        };
        this.$get = ['$q', '$location', '$window', function($q, $location, $window) {
            return {
                response: function(response){
                    return response || $q.when(response);
                },
                responseError: function(rejection) {
                    $q.when(rejection.status == 401)
                    if (rejection.status === 401) {
                        if(redirectUrl) {
                            $location.path(redirectUrl);
                            var authUrl = $location.absUrl();
                            $window.location.href = authUrl;
                        }
                    } else if (rejection.status === 429) {
                        $location.path('/error');
                    }
                    return $q.reject(rejection);
                }
            }
        }];
})

I hope this helps and you can refer to the full implementation which is a little hackish as it is a POC if you need more information.

like image 166
seetdev Avatar answered Nov 07 '22 06:11

seetdev


If you only need to get a timeline, you can use ng-tweets

If you want a purely client-side approach, and you only need to pull a timeline, you can use the ng-tweets module available here:

https://github.com/forwardadvance/ng-tweets

It works by scraping the official Twitter widget API, and reverse engineering a JSON feed, so you don't need an auth token or secret or any server-side support code.

Disclaimer

I am the author of this module. I wrote it to solve exactly this problem, not wishing to exposed oauth data clientside, or to use the official widget HTML.

like image 39
superluminary Avatar answered Nov 07 '22 06:11

superluminary


ALl your twitter requests need to be authorized:

https://dev.twitter.com/docs/auth/authorizing-request

so you will need to pass some OAuth data in your request header per document above

like image 1
Vlad Gurovich Avatar answered Nov 07 '22 07:11

Vlad Gurovich