Adaptation of WP7IsolatedStorageCredentials only partially worked once

Apr 3, 2013 at 7:53 PM
I am trying to set up OAuth for Windows Phone 7, and tried adapting TwitterAuthPage.xaml and TwitterAuthPage.xaml.cs from the WP7IsolatedStorageCredentials project on this page.
using System;
using System.Linq;
using System.Windows;
using System.Windows.Navigation;
using LinqToTwitter;
using Microsoft.Phone.Controls;

namespace WP7IsolatedStorageCredentialsDemo
{
    public partial class OAuth : PhoneApplicationPage
    {
        PinAuthorizer pinAuth;

        public OAuth()
        {
            InitializeComponent();
            Loaded += Page_Loaded;
            OAuthWebBrowser.LoadCompleted += OAuthWebBrowser_LoadCompleted;
        }

        void OAuthWebBrowser_LoadCompleted(object sender, NavigationEventArgs e)
        {
            EnterPinTextBlock.Visibility = Visibility.Visible;
            PinTextBox.IsEnabled = true;
            AuthenticateButton.IsEnabled = true;
        }

        void Page_Loaded(object sender, RoutedEventArgs e)
        {
            pinAuth = new PinAuthorizer
            {
                Credentials = new IsolatedStorageCredentials 
                { 
                    ConsumerKey = //My consumer key  
                    ConsumerSecret = //My consumer secret key
                },
                UseCompression = true,
                GoToTwitterAuthorization = pageLink => Dispatcher.BeginInvoke(() => OAuthWebBrowser.Navigate(new Uri(pageLink, UriKind.Absolute)))
            };

            pinAuth.BeginAuthorize(
                resp => Dispatcher.BeginInvoke(() => 
                {
                    switch (resp.Status)
                    {
                        case TwitterErrorStatus.Success:
                            break;
                        case TwitterErrorStatus.TwitterApiError:
                        case TwitterErrorStatus.RequestProcessingException:
                            MessageBox.Show(
                                resp.Exception.ToString(),
                                resp.Message,
                                MessageBoxButton.OK);
                            break;
                    }
                }));
        }

        private void AuthenticateButton_Click(object sender, RoutedEventArgs e)
        {
            pinAuth.CompleteAuthorize(
                PinTextBox.Text,
                completeResp => Dispatcher.BeginInvoke(() =>
                {
                    switch (completeResp.Status)
                    {
                        case TwitterErrorStatus.Success:
                            var cred = pinAuth.Credentials as IsolatedStorageCredentials;
                            cred.Save();
                            NavigationService.GoBack();
                            break;
                        case TwitterErrorStatus.TwitterApiError:
                        case TwitterErrorStatus.RequestProcessingException:
                            MessageBox.Show(
                                completeResp.Exception.ToString(),
                                completeResp.Message,
                                MessageBoxButton.OK);
                            break;
                    }
                }));
        }
    }
}
The only changes I made were to add my consumer and consumer secret keys, and to change both .Error properties of TwitterAsyncReponse objects to .Exception properties (it differs between library versions).

The first time I ran it, I was able to get the PIN from Twitter. The code only failed after I entered the PIN and hit the authorize button.

Every subsequent time I've run it, I haven't even been able to get the Twitter login screen to load inside the phone:WebBrowser control. The Page_Loaded method is the last thing to complete, and inside of that, the breakpoint I put on the opening brace under resp => Dispatcher.BeginInvoke(() => never gets hit.

I would guess this is an issue with Twitter storing cookies and thinking I should already be logged in, but I'm not sure. I tried clearing WebBrowser's Twitter cookies with this code:
void ClearCookies(string uriString)
{
    Uri uri = new Uri(uriString, UriKind.Absolute);
    //OAuthWebBrowser.Navigate(login);

    HttpWebRequest _webRequest;
    CookieContainer _cookieContainer = new CookieContainer();
    _webRequest = (HttpWebRequest)HttpWebRequest.Create(uri);
    _webRequest.CookieContainer = _cookieContainer;
    var cookies = _cookieContainer.GetCookies(uri);

    foreach (System.Net.Cookie cookie in cookies)
    {
        cookie.Discard = true;
        cookie.Expired = true;
    }
}

ClearCookies("http://www.twitter.com/login");
ClearCookies("http://api.twitter.com/oauth/request_token");
ClearCookies("http://api.twitter.com/oauth/authorize");
ClearCookies("http://api.twitter.com/oauth/access_token");
But when debugging, I saw no stored cookies for any of those URLs, so of course the behavior of the program didn't change.

If this does sound like a cookie issue, is there a different URL I should be targeting? If not, any idea what's going on? Thanks!
Coordinator
Apr 4, 2013 at 5:17 AM
The IsolatedStorageCredentials saves credentials to isolated storage. If you only have ConsumerKey and ConsumerSecret, the authorizer will invoke GoToTwitterAuthorization. Once you've authorized a user, IsolatedStorageCredentials saves all four keys in the user's Isolated Storage so that you don't have to authorize anymore. There's a Clear option on IsolatedStorageCredentials that lets you clear out the old credentials to force another Authorization session.

If you're testing your authorization workflow, you could temporarily replace IsolatedStorageCredentials with InMemoryCredentials to keep from needing to clear the credentials each time.

Also, if IsolatedStorageCredentials doesn't do what you want, you can create your own type derived from IOAuthCredentials. You can look at how other types implement IOAuthCredentials for ideas.

@JoeMayo
Apr 5, 2013 at 8:42 PM
Thanks a lot!