In my last post I wrote about the Silverlight WebBrowser control on Windows Phone 7 and how to communicate with a web page hosted inside the control and your Windows Phone 7 app. The example in that post was pretty trivial, so why not try something like OAuth and Twitter.
For more background on how OAuth and Twitter work check the Authentication Overview on dev.twitter.com.
In short here is the process (overly simplified) to authenticate a twitter user
- Register your app with Twitter and get a key
- Within app, get an request token
- With the WebBrowser control, navigate to Authentication URL
- Wait till the user authenticates.
- Get an access token
- Make secure calls
After becoming familiar with OAuth, first thing I decided to do was find an OAuth library for Silverlight. The one I found most useful and easily portable to Windows Phone 7 was sample code in the book Professional Twitter Development by Daniel Crenna. Unfortunately, this did not compile without a few changes on WP7. Here is a quick summary of the changes I made
- Change all HttpWebRequests to be async since sync requests are not supported
- Added callback param to all methods to get responses back to the UI
- Created and OAuthEventArgs class
- Modified support to POST web requests
- Added helper methods to ParseQueryString and HexEscape characters
- Added a TwitterOAuth class to contain all tokens, Urls and various other items.
Next thing I had to do was wire up the code to enable the user to authenticate via OAuth with Twitter. Basically all you have to do is get a “request token” then navigate to the “authentication Url” for the user to enter their credentials. Here is the code
OAuth.GetRequestToken(m_twitterOAuth.RequestTokenUrl,
m_twitterOAuth.ConsumerKey,
m_twitterOAuth.ConsumerSecret,
new EventHandler<OAuthEventArgs>((o, args) =>
{
if (args.IsError)
this.Dispatcher.BeginInvoke(() => MessageBox.Show(args.ErrorMessage));
else
{
//extract the items
Dictionary<string, string> results =
Helpers.ParseQueryString(args.Response);
foreach (var item in results)
{
if (item.Key.Equals("oauth_token"))
m_twitterOAuth.Token = item.Value;
else if (item.Key.Equals("oauth_token_secret"))
m_twitterOAuth.TokenSecret = item.Value;
}
//Wait till the browser loads
while (!m_browserLoaded)
Thread.Sleep(100);
//once loaded invoke the browser to go to twitter auth page
this.Dispatcher.BeginInvoke(() =>
{
webBrowser1.Navigate(new Uri(m_twitterOAuth.AuthenticationUrl));
});
}
}));
When asking for a request token, you can specify a callback url that twitter will navigate to when the user successfully authenticates. Next step is to create an HTML page that will invoke a method within our WP7 application. The HTML Page is as follows and is very straight forward.
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>TwitterCallback</title>
<script type="text/javascript">
function InvokeApp(input) {
window.external.Notify(window.location.href);
}
</script>
</head>
<body onload="InvokeApp()">
</body>
</html>
The method inside our WP7 app will parse the url which contains details on the authentication then goes out and gets the access token to make secure calls
void webBrowser1_ScriptNotify(object sender, NotifyEventArgs e)
{
//we are back from authentication so extract the verifier
try
{
Uri uri = new Uri(e.Value);
//parse the query string
Dictionary<string, string> results = Helpers.ParseQueryString(uri.Query);
foreach(var item in results)
{
if (item.Key.Equals("oauth_verifier"))
m_twitterOAuth.Verifier = item.Value;
}
//hide the web browser control
this.Dispatcher.BeginInvoke(() =>
{
textBlock1.Text = "Contacting twitter to get access to your twitter
account. Please be patient :)";
textBlock1.Visibility = System.Windows.Visibility.Visible;
webBrowser1.Visibility = System.Windows.Visibility.Collapsed;
});
//now that we have the verifier get the access token
OAuth.GetAccessToken(m_twitterOAuth.AccessTokenUrl,
m_twitterOAuth.ConsumerKey,
m_twitterOAuth.ConsumerSecret,
m_twitterOAuth.Token,
m_twitterOAuth.TokenSecret,
new EventHandler<OAuthEventArgs>((obj, args) =>
{
//handler when the get access token call returns
if (args.IsError)
this.Dispatcher.BeginInvoke(() =>
MessageBox.Show(args.ErrorMessage));
else
{
//extract the items
results = Helpers.ParseQueryString(args.Response);
foreach (var item in results)
{
if (item.Key.Equals("oauth_token"))
m_twitterOAuth.Token = item.Value;
else if (item.Key.Equals("oauth_token_secret"))
m_twitterOAuth.TokenSecret = item.Value;
else if (item.Key.Equals("user_id"))
m_twitterOAuth.UserId = item.Value;
else if (item.Key.Equals("screen_name"))
m_twitterOAuth.ScreenName = item.Value;
}
//update the label
this.Dispatcher.BeginInvoke(() =>
{
MessageBox.Show(textBlock1.Text,
"Authorized for Twitter", MessageBoxButton.OK);
btnSignOut.Visibility = btnPostTweet.Visibility =
txtTweet.Visibility = Visibility.Visible;
textBlock1.Visibility = Visibility.Collapsed;
});
//save the settings
SaveTwitterOAuth();
}
}));
}
catch (Exception ex)
{
this.Dispatcher.BeginInvoke(() => MessageBox.Show(ex.Message));
}
}
Now that we are authenticated we can make a ‘Tweet’ from with our application as follows
private void btnPostTweet_Click(object sender, RoutedEventArgs e)
{
if (txtTweet.Text.Length > 140)
{
MessageBox.Show("Message is greater than 140. Cannot post");
}
else
{
OAuth.GetProtectedResource(
string.Format(m_twitterOAuth.StatusUpdateUrl,
HttpUtility.UrlEncode(txtTweet.Text)),
"POST",
m_twitterOAuth.ConsumerKey,
m_twitterOAuth.ConsumerSecret,
m_twitterOAuth.Token,
m_twitterOAuth.TokenSecret,
new EventHandler<OAuthEventArgs>((obj, args) =>
{
//the post is back so parse the response
//handler when the get access token call returns
if (args.IsError)
this.Dispatcher.BeginInvoke(() =>
MessageBox.Show(args.ErrorMessage));
else
{
this.Dispatcher.BeginInvoke(() =>
{
MessageBox.Show(args.Response,"Tweet Posted",
MessageBoxButton.OK);
txtTweet.Text = string.Empty;
});
UpdateUsernameLabel();
}
}));
}
}
Here is a screen shot of a test tweet
One of the advantages of using OAuth with Twitter is you get your ‘application name’ in the ‘via’ section instead of it saying ‘posted from web’. Also, since Basic Authentication is no longer supported by Twitter, your only option is either OAuth or XAuth. Considering with XAuth you have to email twitter and convince them to give you access to that, OAuth is the easier way to go.
Here are some screen shots of the Windows Phone 7 client.

You can download the source code here. I have no plans on building a Twitter client for Windows Phone 7 as I have a feeling someone out there is probably building one :)
Any feedback let me know via here or via Twitter.
NOTES: The app will not compile until you remove the #error to add your registered app key. Also, make sure you change the timezone and set the correct time on the emulator or else the OAuth signature generation will not work.