ProgrammingJavascriptCareerProductivityGadgetsASP.NETWeb Design

How To Post A Tweet Using C# For Single User

Written by
Published on
Modified on
Filed under
How To Post A Tweet Using C# For Single User

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);
    ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
    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();
}

Update 2019: Starting on July 25th, 2019 Twitter began requiring TLS 1.2 as the security protocol. https://twittercommunity.com/t/removing-support-for-legacy-tls-versions-1-0-1-1-on-twitter/126648


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.



Walter Guevara is a software engineer, startup founder and currently teaches programming for a coding bootcamp. He is currently building things that don't yet exist.

Comments

S
Simon
7/2/2016 4:22:14 AM
Hey your code working thanks to you. but i want an url also pass with the tweet so how can i do this?
Walt
7/6/2016 12:32:59 AM
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!
G
Gary Ewan Park
7/13/2016 5:32:59 AM
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!
Walt
7/13/2016 12:28:01 PM
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!
G
Gary Ewan Park
7/13/2016 12:47:34 PM
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.
Walt
7/13/2016 1:43:51 PM
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!
c
camiloch
11/24/2016 6:30:05 PM
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.
Walt
3/9/2017 3:40:20 PM
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.
m
mario
1/2/2017 9:16:32 PM
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.
Walt
3/9/2017 4:48:10 PM
Hashtags are separate from regular strings I believe! They have to be posted as Entity objects. Will update this post soon with that info!
s
stenly
3/26/2017 2:12:50 AM
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
Walt
3/26/2017 11:24:19 AM
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!
s
stenly
3/28/2017 12:28:29 AM
Great job! :)
Walt
3/28/2017 1:51:04 PM
Thank you kindly!
T
Truong Le
2/4/2018 6:59:27 AM
Hi, How do you upload image attachment? thanks!
Walt
11/4/2018 2:12:45 PM
Good question! You'll need a different type of endpoint and request. Check out the following for more info https://developer.twitter.com/en/docs/media/upload-media/overview
K
Kevin
8/9/2019 9:01:24 AM
This was very useful to me. One update needs to be made though. Twitter now requires TLS 1.2. So before creating the request call ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; https://twittercommunity.com/t/removing-support-for-legacy-tls-versions-1-0-1-1-on-twitter/126648/2
Walt
10/10/2019 2:12:18 PM
Glad you found it useful Kevin! And many thanks for that clarification! Definitely helps this post out.
H
Harsha
2/20/2020 3:04:03 AM
[ The underlying connection was closed: An unexpected error occurred on a send]. While using your code I am getting this error. Could you please give me some inputs?
Walter
2/21/2020 2:39:55 PM
Hello there Harsha. Many thanks for the question. Twitter now requires TLS 1.2. So before creating the request call ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; https://twittercommunity.com/t/removing-support-for-legacy-tls-versions-1-0-1-1-on-twitter/126648/2 We can thank Kevin for pointing it out in the comments above! Hope that helps!
H
Harsha
2/25/2020 11:18:07 PM
Thanks Kevin and Walter for the update. But adding that I got this error "[Additional information: The remote server returned an error: (401) Unauthorized.]". Any idea how to solve this??
Walter
2/26/2020 7:10:36 PM
That's interesting. ?? Well, it looks like its attempting to make the connection now at least. The main time that I see 401 issues, is when there is any slight issue with the request headers. And also if the tweet you are sending is a duplicate of a recent tweet. So you could try changing the text each time as you test, just to ensure that isn't the case!
H
Harsha
2/26/2020 9:56:30 PM
Thanks for the reply Walter. I'll try that and let you know what was my mistake.
N
Neo
7/25/2020 7:53:13 PM
Hey there, thanks for the great code, works awesome...not sure why so many other examples just dont work...is there a chance i could ask for some help with trying too get a specific users timeline with this method, instead of a 3rd party api call, that was the reason for coming to your website, you are probably onje of the only ones in csharp that does it without a 3rd party...of course i could download any of the frameworks that are bloated and go through thousands of lines of code, or just use yours....would be nice to get a timeline...dont know if i need to use same auth tokens or just use a public display....i think if you are logged in with keys you can get protected friend timelines or following timelines...not sure....
J
José
7/26/2020 7:15:01 AM
GREAT JOB!! YOU SAVED MY DAY!!!
D
Dad El Carbo
4/30/2021 5:39:54 AM
Thanks so much. posted my first tweet with your help. Any idea how to POST media ?
T
Tle
11/29/2021 10:16:39 PM
I was getting a 401 error. There is something wrong in generating the Authorization string. I tried just replacing this with the auto-generated string with Postman and it worked. Please give me any ideas.
m
milds
1/18/2023 9:53:45 AM
Hi Walter. Your code is very helpful but the link to the source code appear to be broken.
m
milds
1/18/2023 9:58:43 AM
Nevermind Walter its working fine
Walter
1/19/2023 8:44:10 AM
Glad to hear it! And a thank you for the kind words!

Developer Poll

Q:

Stay up to date

Sign up for my FREE newsletter. Get informed of the latest happenings in the programming world.

Add a comment

Keep me up to date on the latest programming news
Add Comment

Stay up to date

Get informed of the latest happenings in the programming world.

No thanks