C# console application Streaming API 1.1 + Oauth


#1

I have a C# console application that connected to Streaming API with username and password and download tweets for the keywords I wanted. It was using https://stream.twitter.com/1.1/statuses/filter.json.

I wrote a code to add OAuth, but I am getting a 400 error. Can anyone pls provide me code or direct me to an opensource project. Or just give me some tips.


#2

Hi, hopefully something on this page will work for you: https://dev.twitter.com/docs/twitter-libraries


#3

I am also having the issue with the basic authentication (username and password) and am now coding the oauth.

For the basic authentication I had the following set up

        string url = @"https://stream.twitter.com/1.1/statuses/filter.json";
        HttpWebRequest webRequest;
        HttpWebResponse webResponse;
        StreamReader streamReader;
        webRequest = (HttpWebRequest)WebRequest.Create(url);
        webRequest.Credentials = new NetworkCredential(username, password);
        webRequest.Timeout = 10000;
        Encoding encode = Encoding.GetEncoding("utf-8");
        webRequest.Method = "POST";
        webRequest.ContentType = "application/x-www-form-urlencoded";
        byte[] postData = encode.GetBytes(ruleFormatted);
        webRequest.ContentLength = postData.Length;
        Stream twitterPost = webRequest.GetRequestStream();
        twitterPost.Write(postData, 0, postData.Length);
        twitterPost.Close();

        webResponse = (HttpWebResponse)webRequest.GetResponse();
        streamReader = new StreamReader(webResponse.GetResponseStream(), encode);

For the new oauth I am maintaining most of this code, the only change is replacing
webRequest.Credentials = new NetworkCredential(username, password);
with
webRequest.Headers.Add(“Authorization”, CreateAuthHeader(account, url));

BUT I am still getting the 401 error

The header I am sending looks like this:

{Authorization: OAuth oauth_nonce=“NjM1MDY3MjcyNDQ2NzY0MTgy”, oauth_signature_method=“HMAC-SHA1”, oauth_timestamp=“1371126845”, oauth_consumer_key=“iu0NweCEqwVWIz8OOE6g”, oauth_token=“1079814948-vc90CLccGLuYVQkX7hSVjrftg8Xeivg2wTSPDGv”, oauth_signature=“s2oYMa8juPaTCuSuxmoWdLy9TUQ%3D”, oauth_version=“1.0A”
}

I have also tried this with oauth_version = “1.0”

Any input greatly appreciated.


#4

Do you have the body of the 401 response?

I’m not entirely sure what might be the problem. It seems that if you’re using “CreateAuthHeader(account, url)” to generate your OAuth header - there’s not enough information being passed - particularly the form post data is not being considered when generating the signature. Try using the OAuth tool (a tab on the application settings page) to generate a signature for a specific request and see whether your code is capable of generating the same signature given the same inputs.


#5

Hi @kurrik I am using the following article to build the oauth

http://www.codeproject.com/Articles/247336/Twitter-OAuth-authentication-using-Net, all of the code is currently placed in my CreateAuthHeader method.

The error I am seeing is:

{System.Net.WebException: The remote server returned an error: (401) Unauthorized.}


#6

Hi @kurrik,

I am using the following article for my oauth, http://www.codeproject.com/Articles/247336/Twitter-OAuth-authentication-using-Net.

I have confirmed that the oauth I am sending is good as I am able to call https://api.twitter.com/1.1/lists/statuses.json and get data returned.

I am still unable to successfully call the streaming API https://stream.twitter.com/1.1/statuses/filter.json.

Here is a copy of my code, I have rejigged the code which works for lists.

public void Stream()
{
//OAuth stuff
var oauth_consumer_key = “consumer key goes here”;
var oauth_consumer_secret = “secret goes here”;

        var oauth_token = "access token goes here";
        var oauth_token_secret = "secret token goes here";

        var oauth_version = "1.0";
        var oauth_signature_method = "HMAC-SHA1";
        var oauth_nonce = Convert.ToBase64String(
                                          new System.Text.ASCIIEncoding().GetBytes(
                                               DateTime.Now.Ticks.ToString()));
        var timeSpan = DateTime.UtcNow
                                          - new DateTime(1970, 1, 1, 0, 0, 0, 0,
                                               DateTimeKind.Utc);
        var oauth_timestamp = Convert.ToInt64(timeSpan.TotalSeconds).ToString();
        var slug = "libraries-and-news-sites";
        var owner_screen_name = "deskfeed";
        //var resource_url = "https://api.twitter.com/1.1/lists/statuses.json";
        var resource_url = "https://stream.twitter.com/1.1/statuses/filter.json";
        
        //these MUST be in alphabetical order!!!
        var baseFormat = "oauth_consumer_key={0}&oauth_nonce={1}&oauth_signature_method={2}" +
        "&oauth_timestamp={3}&oauth_token={4}&oauth_version={5}&follow={6}&track={7}";


        var baseString = string.Format(baseFormat,
                                    oauth_consumer_key,
                                    oauth_nonce,
                                    oauth_signature_method,
                                    oauth_timestamp,
                                    oauth_token,
                                    oauth_version,
                                    Uri.EscapeDataString("216299334,15735744"),
                                    Uri.EscapeDataString("stephenfry")
                                    );

        baseString = string.Concat("POST&", Uri.EscapeDataString(resource_url),
                     "&", Uri.EscapeDataString(baseString));

        var compositeKey = string.Concat(Uri.EscapeDataString(oauth_consumer_secret),
                                "&", Uri.EscapeDataString(oauth_token_secret));

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

        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)
                        );

        ServicePointManager.Expect100Continue = false;

        // Actual Twitter request
        var getBody = "?follow=216299334,15735744&track=stephenfry";
        resource_url += getBody;
        HttpWebRequest request = (HttpWebRequest)WebRequest.Create(resource_url);

        request.Headers.Add("Authorization", authHeader);

        request.Method = "POST";
        request.ContentType = "application/x-www-form-urlencoded";

        WebResponse response = request.GetResponse();
        StreamReader streamReader = new StreamReader(response.GetResponseStream());

        while (!streamReader.EndOfStream)
        {
            string post = streamReader.ReadLine();
        }
    } 

Note I have tried this with both a GET and a POST, same error.

Any input greatly appreciated.


#7

More progress on this, I have rejiggied the 3rd party app Twitterizer, which I currently use for calls to Twitter non streaming APIs, and this seem to be working well and I am now successfully streaming the https://stream.twitter.com/1.1/statuses/filter.json API.


#8

@_BiddyLiddy,
Can you post the code that you got it to work with please, thanks in advance.

I have successfully gotten the bearer token, but I cannot connect with the token that I receive.

Here is my code after receiving the bearer token

var authHeader = “Bearer " + bearer;
stream_url = https://stream.twitter.com/1.1/statuses/filter.json?language=en”;

string postparameters = keywords == string.Empty ? string.Empty : “&track=” + keywords + (ConfigurationManager.AppSettings[“follow_userid”].Length == 0 ? string.Empty : “&follow=” + ConfigurationManager.AppSettings[“follow_userid”]) + (ConfigurationManager.AppSettings[“location_coord”].Length == 0 ? string.Empty : “&locations=” + ConfigurationManager.AppSettings[“location_coord”]);

webRequest = (HttpWebRequest)WebRequest.Create(stream_url + postparameters);
webRequest.Headers.Add(“Authorization”, authHeader);

                    //webRequest.Timeout = -1;
                    webRequest.UserAgent = "myPolling";                
                    webRequest.Headers.Add("Accept-Encoding", "gzip");
                    Encoding encode = System.Text.Encoding.GetEncoding("utf-8");
                    if (postparameters.Length > 0)
                    {
                       webRequest.Method = "POST";
                       //webRequest.ContentType = "application/x-www-form-urlencoded";

                        byte[] _twitterTrack = encode.GetBytes(postparameters);

                        webRequest.ContentLength = _twitterTrack.Length;
                        Stream _twitterPost = webRequest.GetRequestStream();
                        _twitterPost.Write(_twitterTrack, 0, _twitterTrack.Length);
                        _twitterPost.Close();
                    }

                    webResponse = (HttpWebResponse)webRequest.GetResponse();

I am getting the “401 Unauthorized error”. Any help will be greatly appreciated.


#9

Can you post your code of the fix you discovered please.


#10

Hi @kurrik im struggling in that error can yo help me how to fix this error:
The remote server returned an error: (401) Unauthorized.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.Net.WebException: The remote server returned an error: (401) Unauthorized.

Source Error:

Line 294: finally
Line 295: {
Line 296: webRequest.GetResponse().GetResponseStream().Close();
Line 297: responseReader.Close();
Line 298: responseReader = null;


#11

Bearer tokens are not supported on the streaming API unfortunately. You’ll have to use full OAuth signing.


#12

Hello there,

I can see that this discussion has been created not that long ago so I would like to provide an example of Filtered Stream using Tweetinvi (http://tweetinvi.codeplex.com/) because I think it will help a lot of developers to use Twitter streaming API in C#.

IToken token = new Token("userKey", "userSecret", "consumerKey", "consumerSecret"); FilteredStream stream = new FilteredStream(); stream.AddTrack("tweetinvi c#"); stream.StartStream(token, tweet => Console.Writeline(tweet.Text));

Hope this helps :slight_smile:


#13

was this sorted mate? i’d like to do the same thing. its not helpful that the error messages arent very descriptive.


#14

It dose not work!
401 error occurs.
I can not solve this problem.


#15

try to encode comma as ‘%2C’ or ‘%2c’. It is wondering, but stream api case sensitive!