Post to Twitter with DotNetOpenAuth

DotNetOpenAuth_TwitterAPI

A few weeks ago, I started looking into using the Twitter API for automatic, event-based status updates in an application. I wanted to understand what was going on, so I didn’t want to simply download Twitterizer or LINQ to Twitter. Learning OAuth has been a challenge, to put it lightly. I’ve learned a lot, but I’m still pretty clumsy with it. Today, I found out about a new open source project that seems like just what I needed: DotNetOpenAuth.

Using DotNetOpenAuth, I was able to create a functional console application that posts to Twitter in about 200 lines of code. This post will walk you through the steps.

The first thing you need to do is create a new Twitter application. Go to dev.twitter.com, sign in (or sign up), and create the application. If you want to post status updates with your application—like we’re doing here—be sure to click to the Settings tab and change the Application Type to Read and Write.

Once you’ve created your application with Twitter, it’s time to create your project in Visual Studio. I’ll be using a console application in an effort to keep it simple. The first thing you’ll want to do after creating the project is install the DotNetOpenAuth NuGet package. (Not sure how to use NuGet? Start here!)

Now it’s time to get down to business. We’re going to start by creating a token manager. Most of the tutorials online seem to use a simple, in-memory token manager, and I’m going to follow suit. In a real application, you’ll want to store the access tokens and access token secrets so that you don’t have to authorize each time the application runs.

namespace adamprescott.net.TweetConsole
{
    using DotNetOpenAuth.OAuth.ChannelElements;
    using DotNetOpenAuth.OAuth.Messages;
    using DotNetOpenAuth.OpenId.Extensions.OAuth;
    using System;
    using System.Collections.Generic;

    public class TokenManager : IConsumerTokenManager
    {
        private static Dictionary<string, string> TokenSecrets = 
            new Dictionary<string, string>();

        public TokenManager(string consumerKey, string consumerSecret)
        {
            ConsumerKey = consumerKey;
            ConsumerSecret = consumerSecret;
        }

        public string ConsumerKey { get; private set; }

        public string ConsumerSecret { get; private set; }

        public string GetTokenSecret(string token)
        {
            return TokenSecrets[token];
        }

        public void StoreNewRequestToken(UnauthorizedTokenRequest request,
            ITokenSecretContainingMessage response)
        {
            TokenSecrets[response.Token] = response.TokenSecret;
        }

        public void ExpireRequestTokenAndStoreNewAccessToken(
            string consumerKey,
            string requestToken,
            string accessToken,
            string accessTokenSecret)
        {
            TokenSecrets.Remove(requestToken);
            TokenSecrets[accessToken] = accessTokenSecret;
        }

        public TokenType GetTokenType(string token)
        {
            throw new NotImplementedException();
        }

        public void StoreOpenIdAuthorizedRequestToken(string consumerKey,
            AuthorizationApprovedResponse authorization)
        {
            TokenSecrets[authorization.RequestToken] = String.Empty;
        }
    }
}

The next thing we need is a consumer wrapper. This wrapper is where we’ll specify the OAuth token URLs and expose three methods that we’ll use from our main application: BeginAuth, CompleteAuth, and PrepareAuthorizedRequest.

namespace adamprescott.net.TweetConsole
{
    using DotNetOpenAuth.Messaging;
    using DotNetOpenAuth.OAuth;
    using DotNetOpenAuth.OAuth.ChannelElements;
    using System.Collections.Generic;
    using System.Net;

    public class TwitterConsumer
    {
        private string _requestToken = string.Empty;

        public DesktopConsumer Consumer { get; set; }
        public string ConsumerKey { get; set; }
        public string ConsumerSecret { get; set; }

        public TwitterConsumer(string consumerKey, string consumerSecret)
        {
            ConsumerKey = consumerKey;
            ConsumerSecret = consumerSecret;

            var providerDescription = new ServiceProviderDescription
            {
                RequestTokenEndpoint = new MessageReceivingEndpoint(
                    "https://api.twitter.com/oauth/request_token",
                    HttpDeliveryMethods.PostRequest),
                UserAuthorizationEndpoint = new MessageReceivingEndpoint(
                    "https://api.twitter.com/oauth/authorize",
                    HttpDeliveryMethods.GetRequest),
                AccessTokenEndpoint = new MessageReceivingEndpoint(
                    "https://api.twitter.com/oauth/access_token", 
                    HttpDeliveryMethods.GetRequest),
                TamperProtectionElements = new ITamperProtectionChannelBindingElement[] 
                {
                    new HmacSha1SigningBindingElement()
                }
            };

            Consumer = new DesktopConsumer(
                providerDescription,
                new TokenManager(ConsumerKey, ConsumerSecret));
            return;
        }

        public string BeginAuth()
        {
            var requestArgs = new Dictionary<string, string>();
            return Consumer
                .RequestUserAuthorization(requestArgs, null, out _requestToken)
                .AbsoluteUri;
        }

        public string CompleteAuth(string verifier)
        {
            var response = Consumer.ProcessUserAuthorization(
                _requestToken, verifier);
            return response.AccessToken;
        }

        public HttpWebRequest PrepareAuthorizedRequest(
            MessageReceivingEndpoint endpoint,
            string accessToken, 
            IEnumerable<MultipartPostPart> parts)
        {
            return Consumer.PrepareAuthorizedRequest(endpoint, accessToken, parts);
        }

        public IConsumerTokenManager TokenManager
        {
            get
            {
                return Consumer.TokenManager;
            }
        }
    }
}

All that’s left to do now is put it all together. The main application needs your Twitter application’s consumer key and consumer secret. (Both of those values can be found on the Details tab of the Twitter application.) Those values are passed to the consumer wrapper which can then produce an authorization URL. We’ll prompt the user for credentials by opening the URL in a web browser. The authorization process will be completed when the user enters their PIN from Twitter into the console application. Once authorized, the application can post to Twitter on behalf of the user. I added a simple loop that prompts the user and tweets their input.

namespace adamprescott.net.TweetConsole
{
    using DotNetOpenAuth.Messaging;
    using System;
    using System.Diagnostics;

    class Program
    {
        const string _consumerKey = "~consumerkey~";
        const string _consumerSecret = "~consumersecret~";
        private TwitterConsumer _twitter;

        static void Main(string[] args)
        {
            var p = new Program();
            p.Run();
        }

        public Program()
        {
            _twitter = new TwitterConsumer(_consumerKey, _consumerSecret);
        }

        void Run()
        {
            var url = _twitter.BeginAuth();
            Process.Start(url);
            Console.Write("Enter PIN: ");
            var pin = Console.ReadLine();
            var accessToken = _twitter.CompleteAuth(pin);

            while (true)
            {
                Console.Write("Tweet ('x' to exit) /> ");
                var tweet = Console.ReadLine();
                if (string.Equals("x", tweet, StringComparison.CurrentCultureIgnoreCase))
                {
                    break;
                }
                Tweet(accessToken, tweet);
            }
        }

        void Tweet(string accessToken, string message)
        {
            var endpoint = new MessageReceivingEndpoint(
                "https://api.twitter.com/1.1/statuses/update.json",
                HttpDeliveryMethods.PostRequest | HttpDeliveryMethods.AuthorizationHeaderRequest);

            var parts = new[]
            {
                MultipartPostPart.CreateFormPart("status", message)
            };

            var request = _twitter.PrepareAuthorizedRequest(endpoint, accessToken, parts);

            var response = request.GetResponse();
        }
    }
}

The full source code for this sample is available on GitHub. Note that you’ll need to provide your application’s consumer key and secret in order to make the sample functional.

Author: Adam Prescott

I'm enthusiastic and passionate about creating intuitive, great-looking software. I strive to find the simplest solutions to complex problems, and I embrace agile principles and test-driven development.

One thought on “Post to Twitter with DotNetOpenAuth”

Leave a comment