Episode 9 of the Coder's Block podcast out now

In this post I'll be showing how to post a Tweet to Twitter using C# and no 3rd party libraries. This is a pure .NET approach, and it's more time consuming but it also gives you a much deeper understanding of how oAuth and Twitter work together behind the scenes. I'll be breaking down the entire process step by step from generating the appropriate tokens to the final signed request getting sent off. As of me writing this, Twitter's REST API is on version 1.1, so it isn't future proof, but for now it'll do the job.

Overview

The REST API's give developers programmatic access to read and write Tweets. This of course requires some type of authentication from the user. The REST API identifies Twitter applications and users using OAuth and responses are available in JSON format.

Posting a tweet programmatically comes down to selecting the corresponding endpoint, and creating a very specific and signed authentication header along with your request. You will need to create a Twitter application before you do anything however, as you do need the corresponding Consumer Token and Access Tokens. And for that, you'll need to create a Twitter Application.

Create A New Application

You can create applications for Twitter here.

How To Post A Tweet Using C# For Single User

You'll need to give your application a name, a description, a website and a callback url. Because I'll be using the API to post tweets for my own personal application, this data isn't publicly visible, but it is still required.

Important: You need to add something to the Callback URL textbox. Even if it doesn't apply to you. The good news is you can add anything really. I added the same URL that was entered into the Website field for example. Once you're done creating an application, you'll be taken to your applications setting page which will some very important info, that you probably shouldn't share with many people.

Important 2: Make sure that your application is set to both read and write under the Access Level, otherwise you will receive an Un-Authorized error message when attempting to post anything to Twitter.

How To Post A Tweet Using C# For Single User

Not done quite just yet. In order to post Tweets on your own behalf, that is, on the account that owns the application, you'll need to use the Single User OAuth capabilities of the Twitter API. So you'll need to generate your own personal Access Tokens. And those tokens can be created in the settings page for your application as well.

How To Post A Tweet Using C# For Single User
How To Post A Tweet Using C# For Single User

These are very important keys and tokens and as such, should not be shared with anyone. These will be the tokens that you will use to sign your requests later on and to make posts on your own behalf. Now that we have these keys, we can move on to implementing the code.

A Few Notes

In order to cut back on abusing the API, Twitter does set some limiting rates on the number of posts that you are allowed per certain time frame. Rates are limited per access token in your possession. For POSTs, there is no maximum limit of of requests set, however there is a limit to the number of posts that you can send at any one time. Hitting that limit will cause a HTTP 403 error to occur.

The Twitter API will also return an error if it detects that your tweet is a duplicate of a recently published tweet.

Authorizing A Twitter Request

Now that the boilerplate is out of the way, we can get started. In order to POST tweets, you'll need to make a request to the following URL.:

https://api.twitter.com/1.1/statuses/update.json

And the HTTP request will look something like this.


POST /1/statuses/update.json?include_entities=true HTTP/1.1
Accept: */*
Connection: close
User-Agent: OAuth gem v0.4.4
Content-Type: application/x-www-form-urlencoded
Content-Length: 76
Host: api.twitter.com

Any programming framework can generate this request with little problem, and in .NET it's no different. This request isn't complete however, as it's missing many many security features that will allow Twitter to tell that a valid person is making that request. And for that, Twitter relies on the oAuth 1.0 protocol. Which means we'll need to add a new request parameter Authorization to our collection. This is where the remainder of the post will focus on, as it is somewhat complex and time consuming.

At the end, the request should look something like the following:

POST /1/statuses/update.json?include_entities=true HTTP/1.1
Accept: */*
Connection: close
User-Agent: OAuth gem v0.4.4
Content-Type: application/x-www-form-urlencoded
Authorization: OAuth oauth_consumer_key="lakjg3jalkjFJkjLkjl4k", oauth_nonce="lfjlktlk265234lkj3l4j534jk5lkj345", oauth_signature="t4kn3lkkjlk3jlklk3lk3jhlkh%3D", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1318622958", oauth_token="588585756-j4lktlk32l4lkj4l2j5l345LKJHDL", oauth_version="1.0"
Content-Length: 76 Host: api.twitter.com

Note the new Authorization header being added. It is comprised of 7 key/value pairs of data that are prefixed with "oauth". Here is a quick summary of each property, and how to generate them using C#. Most are pretty straight forward, except for the oauth_signature, which I'll cover at the end as it's the most complex and most important.

consumer_key: The consumer key identifies the application making the request, and if you followed the steps up above creating your application, you can get that value from your applications setting page.

How To Post A Tweet Using C# For Single User

oauth_nonce: The nonce parameter, or "nonsense" parameter, is a random alphanumeric string that must be unique per request. It essentially tells Twitter if a request has been submitted more than once. Any random alphanumeric character will work here really, so it's up to you how you will take that approach. You can declare a GUID for this, or simply generate a random length and random character string like I did.


    private string GenerateNonce()
    {
        string nonce = string.Empty;
        var rand = new Random();
        int next = 0;
        for (var i = 0; i < 32; i++)
        {
            next = rand.Next(65, 90);
            char c = Convert.ToChar(next);
            nonce += c;
        }

        return nonce;
    }

oauth_signature: See down below:

oauth_signature_method: The signature method used by the Twitter API is "HMAC-SHA1".

oauth_timestamp: The timestamp value indicates when the request was created. This value should be the number of seconds since the Unix epoch at the point the request is generated. Twitter will reject requests which were created too far in the past, so it is important to keep the clock of the computer generating requests in sync with NTP.

The following function in C# will generate the appropriate timestamp.


    public double GenerateTimestamp(DateTime date)
    {
        DateTime origin = new DateTime(1970, 1, 1, 0, 0, 0, 0);
        TimeSpan diff = date.ToUniversalTime() - origin;
        return Math.Floor(diff.TotalSeconds);
    }


oauth_token: There are various ways to get tokens in order to make requests. In the scenario where a single user wants to post to their own timeline, such as what I'll be doing, you can generate native tokens right from your applications settings screen. These tokens can be deleted or reset later on if need be, and once again, should be kept secret.


How To Post A Tweet Using C# For Single User

oauth_version: The oauth_version parameter should always be 1.0 for any request sent to the Twitter API.


The following function will generate the appropriate authorization header. It is essentially a string beginning with "OAuth", followed by the 7 specified oauth parameters percent encoded.



private string GenerateAuthorizationHeader(string status)
{
    string signatureMethod = "HMAC-SHA1";
    string version = "1.0";
    string nonce = GenerateNonce();
    double timestamp = ConvertToUnixTimestamp(DateTime.Now);
    string dst = string.Empty;

    dst = string.Empty;
    dst += "OAuth ";
    dst += string.Format("oauth_consumer_key=\"{0}\", ", Uri.EscapeDataString(oAuthConsumerKey));
    dst += string.Format("oauth_nonce=\"{0}\", ", Uri.EscapeDataString(nonce));
    dst += string.Format("oauth_signature=\"{0}\", ", Uri.EscapeDataString(GenerateOauthSignature(status, nonce, timestamp.ToString())));
    dst += string.Format("oauth_signature_method=\"{0}\", ", Uri.EscapeDataString(signatureMethod));
    dst += string.Format("oauth_timestamp=\"{0}\", ", timestamp);
    dst += string.Format("oauth_token=\"{0}\", ", Uri.EscapeDataString(accessToken));
    dst += string.Format("oauth_version=\"{0}\"", Uri.EscapeDataString(version));
    return dst;
}


Generating The Signature


I left the oauth_signature section on top blank on purpose, because it's more complicated and requires its own area. The signature parameter is percent encoded collection of the authentication parameters and the Twitter message you wish to send, that will be HMAC SHA1 encoded and signed using a specific key.This signature will be sent along with the authorized request above in order to prove that the request wasn't tampered with and that it belongs to the appropriate application.

The signature is comprised of a few different elements, which I'll break down below. Combined and then encrypted, this string will become the signature used in the authentication request.


Request Method and URL


For the purposes of sending a tweet, our request method will be a POST, and the base URL will be:

https://api.twitter.com/1/statuses/update.json

Parameters


There are 7 parameters that we'll need to percent encode and concatenate together using the '&'. These will be the same key/values that we generated for our main authentication request above. That is, the same nonce, timestamp and same tokens. You'll also need your actualy message that you wish to tweet and percent encode that as well under the status parameter. The oAuth specification requires that these values be sorted lexigraphically, that is in alphabetical order.



    string dst = string.Empty;
    dst += string.Format("oauth_consumer_key={0}&", Uri.EscapeDataString(oAuthConsumerKey));
    dst += string.Format("oauth_nonce={0}&", Uri.EscapeDataString(nonce));
    dst += string.Format("oauth_signature_method={0}&", Uri.EscapeDataString(signatureMethod));
    dst += string.Format("oauth_timestamp={0}&", timestamp);
    dst += string.Format("oauth_token={0}&", Uri.EscapeDataString(oauthToken));
    dst += string.Format("oauth_version={0}&", Uri.EscapeDataString(version));
    dst += string.Format("status={0}", Uri.EscapeDataString(status));


Signature Base String


The signature base string is our final string value put together, before it is signed and encrypted. It is comprised of the request method, base url, and the parameter string which we just created above. The steps are as follows:


  • Convert the HTTP Method to uppercase and set the output string equal to this value.
  • Append the ‘&’ character to the output string.
  • Percent encode the URL and append it to the output string.
  • Append the ‘&’ character to the output string.
  • Percent encode the parameter string and append it to the output string.

That will result in something like this:


POST&https%3A%2F%2Fapi.twitter.com%2F1%2Fstatuses%2Fupdate.json&oauth_consumer_key%3Dxvz1evFS4wEEPTGEFPHBog%26oauth_nonce%3DkYjzVBB8Y0ZFabxSWbWovY3uYSQ2pTgmZeNu2VS4cg%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1318622958%26oauth_token%3D370773112-GmHxMAgYyLbNEtIKZeRNFsMKPR9EyMZeS9weJAEb%26oauth_version%3D1.0%26status%3DHello%2520Ladies%2520%252B%2520Gentlemen%252C%2520a%2520signed%2520OAuth%2520request%2521

Signing Key


Next up, we need to create a key in order to sign our HMAC-SHA1 hash. This key is comprised the oAuth Consumer Secret percent encoded, followed by an '&', followed by the oAuth access token secret also percent encoded. This string combined will become our key.



string signingKey = string.Empty;
signingKey = string.Format("{0}&{1}", Uri.EscapeDataString(oAuthConsumerSecret),Uri.EscapeDataString(accessTokenSecret));


HMAC-SHA1


The last step in generating our signature is to hash our signature base string. And for that we'll need to use the HMACSHA1 class in .NET.



    HMACSHA1 hmac = new HMACSHA1();
    hmac.Key = Encoding.UTF8.GetBytes(signingKey);

    byte[] databuff = System.Text.Encoding.UTF8.GetBytes(signature_base_string);
    byte[] hashbytes = hmac.ComputeHash(databuff);

    return Convert.ToBase64String(hashbytes);


Remember to base 64 encode the final result of the computed hash.


Sending The Final Request


This is the last piece in our puzzle, and we now have a complete authorization header to send off to Twitter.



private void SendTweet(string message)
{
    string authHeader = GenerateAuthorizationHeader(message);
    string postBody = "status=" + Uri.EscapeDataString(message);

    HttpWebRequest authRequest = (HttpWebRequest)WebRequest.Create(oAuthUrl);
    authRequest.Headers.Add("Authorization", authHeader);
    authRequest.Method = "POST";
    authRequest.UserAgent = "OAuth gem v0.4.4";
    authRequest.Host = "api.twitter.com";
    authRequest.ContentType = "application/x-www-form-urlencoded;charset=UTF-8";
    authRequest.ServicePoint.Expect100Continue = false;
    authRequest.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;

    using (Stream stream = authRequest.GetRequestStream())
    {
        byte[] content = Encoding.UTF8.GetBytes(postBody);
        stream.Write(content, 0, content.Length);
    }

    WebResponse authResponse = authRequest.GetResponse();
    authResponse.Close();
}


It's a little time consuming and there are for sure easier ways to post a tweet using code. There are several 3rd party libraries that get the job done much faster. But this is the most barebones way to do it. It doesn't rely on any external code, and it doesn't rely on the built-in oAuth classes that .NET offers even. The full source is down below ready for your copy and paste pleasure. Keys and tokens should be specified in your web.config's app settings.



Comments

S
Simon
Hey your code working thanks to you. but i want an url also pass with the tweet so how can i do this?
7/2/2016 4:22:14 AM
Walt
Awesome to hear! You can actually just pass the URL's like you normally would. For example:

"here is my link http://www.google.com"

And Twitter will render them as links!
7/6/2016 12:32:59 AM
G
Gary Ewan Park
Thank you very much for posting this! I am trying to get this to work, however, when I try to run it, I get the following error message: "The remote server returned an error: (400) Bad Request." Has anything changed in the Twitter API since you posted this that would make the sample you provide not work? Thanks!
7/13/2016 5:32:59 AM
Walt
Hey Gary! You are very welcome. I ran through a few tests on my running code, which hasn't been updated in a while
and everything still seems to be functioning okay.

I have run into this issue before. I'm not too sure what causes it though, but it might fail a few times on occasion
and then just start working all of a sudden. The last time it happened to me I logged in to the Twitter Dev Console and regenerated
the keys and it began working right after. Let me know if that works for you!
7/13/2016 12:28:01 PM
G
Gary Ewan Park
Wasn't sure how to reply to your answer, so thought I would just post again. I figured out what the issue was. I was reading the tokens/keys from Environment Variables, and somehow I had managed to include a tab character at the start of the variable, which was subsequently getting encoded into the auth header, which was throwing everything off. I was able to get this working. Thanks again! Just to let you know (and I hope it is ok, I didn't see anything to suggest it wouldn't be) I have used your excellent work here to create an Addin for the Cake Build system which I work on. You can find that addin here: https://github.com/gep13/Cake.Twitter This means that someone using the Cake Build System would be able to send a tweet when they need to. I have provided attribution about to you for this great work. Please let me know if you have any questions.
7/13/2016 12:47:34 PM
Walt
Excellent! Glad you got it working Gary. It's definitely not a forgiving process for sure.
And that's perfectly ok with me. The more people it helps the merrier I say!
7/13/2016 1:43:51 PM
c
camiloch
Hi, it works nicely, but i have some questions about. Can i reuse the same code to send a private message? how can i do that?. Thank you so much.
11/24/2016 6:30:05 PM
Walt
Will do a separate write up on that! But I believe you can, the only things that would change are the parameters and the request url.
3/9/2017 3:40:20 PM
m
mario
hi, i tried the code and it successfully posted to twitter, however, the hashtags are not included in the twit. All with "#" at the beginning is not included in the posted twit.
1/2/2017 9:16:32 PM
Walt
Hashtags are separate from regular strings I believe! They have to be posted as Entity objects. Will update this post soon with that info!
3/9/2017 4:48:10 PM
s
stenly
Hi, very nice tutorial! Would be great to see the way how to get a user token after authentication to authorize post status on authenticated User behave, so you dont use your token from twitter/dev. Have you elaborated on this one, too? ps: missing text field where I could add my email address :p stenly311 [at] gmail [dot] com
3/26/2017 2:12:50 AM
Walt
Thank you for the kinds words Stenly! Will append this post with that info :) It's on my To Do list. And email field has been added!
3/26/2017 11:24:19 AM
s
stenly
Great job! :)
3/28/2017 12:28:29 AM
Walt
Thank you kindly!
3/28/2017 1:51:04 PM
T
Truong Le
Hi, How do you upload image attachment? thanks!
2/4/2018 6:59:27 AM

Add a comment

"sometimes you have to delete, to find your answer"
Copyright © 2018 thatsoftwaredude.com
humans.txt
TOP SCORES
Score in the top 10 and leave your Instagram handle.
Start
0
snake left
snake up
snake down
snake right