Can we use others @names when authenticating?


#1

We are trying to move to API1.1 so that we can publish our clients tweets to the websites we have built for them. When we do this with our credentials everything works correctly but when we use their @name the request returns a 401.
Effectively by using our consumer secret and OAuth tokens we’re trying to validate our API connection but then need to pull another accounts tweets. Is this possible, orr do we need the @name and password for each of our clients so we effectively authenticate as them? Seems like a limiting model for agencies and third parties if that is the case.
Thanks


#2

Yes, you can load other users’ tweets; statuses/user_timeline has a screen_name parameter, so if I authenticated as me, but passed ‘PipWright’ as the screen_name parameter, I’d get your tweets.


#3

Hi Matt and thanks for the response. Good to know that we can do it, frustrating as to why it’s not working!
I’m assuming most likely result is malformed request or system clock out of synch?


#4

although it can’t be a malformed request otherwise it wouldn’t work when we use our screen_name. We’re checking against the system clock, so that doesn’t appear to be the issue either.

It’s only when we use anothers screen_name does it go bang.


#5

Are you using a library to make the request? Got any code snippets you can post?

I don’t know if it’d be of any help but I’m using a PHP library and I’d do something like this:

$tweets = $connection->get(‘statuses/user_timeline’, array(‘count’ => 100, ‘screen_name’ => ‘PipWright’));

Are you doing something similar? $connection would have been made with my credentials/tokens but this would then return your tweets.


#6

Afternoon Matt
Below is the C# code snippet.
Using a specific users credentials, I can access and display their tweets.
As soon as I add a different screen name & count, I get a 401 Unauthorised error
Even if I add in the screen name of the user whose credentials I’ve authenticated with, I get a 401 Unauthorised error

Any help would be appreciated?

This has been mentioned at various

class Program { static void Main(string[] args) { var oauth_token = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"; var oauth_token_secret = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"; var oauth_consumer_key = "XXXXXXXXXXXXXXXXXX"; var oauth_consumer_secret = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
        var maxRetries = 5;
        var retries = 0;
        var submitted = false;
        string twitterTime = null;

        while (!submitted && retries < maxRetries)
        {
            try
            {

                //Request details
                var oauth_version = "1.0";
                var oauth_signature_method = "HMAC-SHA1";
                var nonceValue = Guid.NewGuid().ToString().Replace("-", string.Empty);
                var oauth_nonce = Convert.ToBase64String(new ASCIIEncoding().GetBytes(DateTime.Now.Ticks.ToString()));
                var baseTime = (retries == 0)
                    ? DateTime.UtcNow
                    : DateTime.ParseExact(twitterTime, "ddd, dd MMM yyyy HH:mm:ss zzz", CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal);

                var timeSpan = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
                var oauth_timestamp = Convert.ToInt64(timeSpan.TotalSeconds).ToString();
                var resource_url = "https://api.twitter.com/1.1/statuses/user_timeline.json";
                var screenName = "screenname";
                var count = "2";
                                                   

                //GS - When building the signature string the params
                //must be in alphabetical order. I can't be bothered
                //with that, get SortedDictionary to do it's thing
                SortedDictionary<string, string> sd =
                    new SortedDictionary<string, string>();

                sd.Add("count", count);
                sd.Add("screen_name", screenName);
                sd.Add("oauth_version", oauth_version);
                sd.Add("oauth_consumer_key", oauth_consumer_key);
                sd.Add("oauth_nonce", oauth_nonce);
                sd.Add("oauth_signature_method", oauth_signature_method);
                sd.Add("oauth_timestamp", oauth_timestamp);
                sd.Add("oauth_token", oauth_token);

                //GS - Build the signature string
                string baseString = String.Empty;
                baseString += "GET" + "&";
                baseString += Uri.EscapeDataString(resource_url) + "&";
                foreach (KeyValuePair<string, string> entry in sd)
                {
                    baseString += Uri.EscapeDataString(entry.Key) + 
                        Uri.EscapeDataString("=") + Uri.EscapeDataString(entry.Value) + Uri.EscapeDataString("&");
                }

                //GS - Remove the trailing ambersand char, remember 
                //it's been urlEncoded so you have to remove the 
                //last 3 chars - %26
                baseString = baseString.Substring(0, baseString.Length - 3);
                
                //Encrypt data
                var compositeKey = string.Concat(Uri.EscapeDataString(oauth_consumer_secret),
                            "&", Uri.EscapeDataString(oauth_token_secret));

                string oauth_signature;
                using (HMACSHA1 hasher = new HMACSHA1(new ASCIIEncoding().GetBytes(compositeKey)))
                {
                    oauth_signature = Convert.ToBase64String(hasher.ComputeHash(new ASCIIEncoding().GetBytes(baseString)));
                }

                //Finish Authentication header
                var headerFormat = "OAuth oauth_consumer_key=\"{0}\", oauth_nonce=\"{1}\", " +
                        "oauth_signature=\"{2}\", oauth_signature_method=\"{3}\", oauth_timestamp=\"{4}\", " +
                        "oauth_token=\"{5}\", oauth_version=\"{6}\"";

                var authHeader = string.Format(headerFormat,
                                        Uri.EscapeDataString(oauth_consumer_key),
                                        Uri.EscapeDataString(oauth_nonce),
                                        Uri.EscapeDataString(oauth_signature),
                                        Uri.EscapeDataString(oauth_signature_method),
                                        Uri.EscapeDataString(oauth_timestamp),
                                        Uri.EscapeDataString(oauth_token),
                                        Uri.EscapeDataString(oauth_version)
                                );
                
                //Disable expect 100 continue header
                ServicePointManager.Expect100Continue = false;
                
                HttpWebRequest request = (HttpWebRequest)WebRequest.Create(resource_url);
                request.Headers.Add("Authorization", authHeader);
                request.Method = "GET";
                request.Timeout = 3 * 60 * 100;
                //request.KeepAlive = false;

                WebResponse response = request.GetResponse();
                string responseData;

                using (StreamReader reader = new StreamReader(response.GetResponseStream()))
                {
                    responseData = reader.ReadToEnd();
                    JavaScriptSerializer jss = new JavaScriptSerializer();
                    List<Tweet> tweets = jss.Deserialize<List<Tweet>>(responseData);
                    
                    //var sw = File.CreateText("C:\\temp\\twitterfeed.txt");
                    //sw.WriteLine(responseData);
                    //Console.WriteLine("File created successfully");
                    var counter = 1;
                    foreach (var tweet in tweets)
                    {
                        if (counter <= 3)
                        {
                            Console.WriteLine(string.Format("Created at: {0}", tweet.Created_At));
                            Console.WriteLine(string.Format("Text: {0}", tweet.Text ));
                        }
                        counter++;
                    }

                    Console.ReadLine();
                }

                submitted = true;
                Console.ReadLine();
            }
            catch (WebException ex)
            {
                if (ex.Response != null)
                {
                    twitterTime = ex.Response.Headers["Date"].Replace(" UTC", " +0000");
                }
                else
                {
                    Console.WriteLine("amount of retries: " + retries);
                    Console.WriteLine(ex.ToString());
                    Console.ReadLine();
                }
            }
            catch (FormatException fe)
            {
                Console.WriteLine(fe.ToString());
                Console.ReadLine();
            }
            finally
            {
                retries++;
            }
            //return responseData; // Or do whatever you want with the response
        }
        Console.WriteLine("amount of retries: " + retries);
        Console.ReadLine();
    }
}

#7

It doesn’t appear that you’re sorting your parameters before assembling the signature base string – it looks like the screen_name parameter would come before the oauth_* parameters.


#8

Afternoon Taylor,
The sorted dictionary orders of the parameters alphabetically, before they’re looped through and assembled to form the base string.


#9

Morning all,.
I’d appreciate some guidance on this. I’m the only person that has encountered the 401 Unauthorised issue when trying to consume tweets with a different screen name.
Adding the screen name is the problem, without that I can consume the tweets associated with the user credentials