ApplicationOnlyAuthorizer on Windows RT and Windows Phone

Oct 2, 2013 at 9:27 PM
Hello, sorry for the English translated by Goggle.
The following snippet of VB.NET code works perfectly when called from a cosole application, instead fails when run in a Windows RT application or Windows Phone.
In particular IsAuthorized is always false, and in fact the BearerToken property is always null, this means that the execution of linq query raises an exception 'Bad Authentication date'.
I found several posts about similar problems, but no one refers to the two environments where my code fails. ApplicationOnlyAuthorizer possible that the class can not be used in these particular environments?
        Dim cred = New LinqToTwitter.InMemoryCredentials() With {.ConsumerKey = RTIWin8ConsumerKey, .ConsumerSecret = RTIWin8ConsumerSecret}
        Dim auth = New LinqToTwitter.ApplicationOnlyAuthorizer() With {.Credentials = cred}
        Try
            Dim twitter = New LinqToTwitter.TwitterContext(auth)
            Dim result = From tweet In twitter.Status
                         Where tweet.Type = LinqToTwitter.StatusType.User And tweet.UserID = RTIUserId

            If Not auth.IsAuthorized Then auth.Authorize()
            Debug.WriteLine(result.Count)
        Catch ex As Exception
            Debug.WriteLine("{0} '{1}' {2}", auth.IsAuthorized, auth.BearerToken, ex)
        End Try
PS: On Windows Phone you need to modify the code so that it uses MaterializedAsyncCallback
Coordinator
Oct 2, 2013 at 9:34 PM
Hi,

I checked in an update a couple days ago so that ApplicationOnlyAuthorizer will work on WinRT. You can download the source code and see the Win8OathDemo. I'm still looking at ApplicationOnlyAuthorizer for Windows Phone. However, you can use a different authorizer for Windows Phone in the meantime - just provide all 4 credentials and it won't need to go through the authorization sequence.

@JoeMayo
Oct 3, 2013 at 8:02 AM
Perfect, thanks for the timely response.
In fact I forgot to state in my post that I use the version of the library published on NuGet.
For now, Windows Phone can wait, when will instead update the version of NuGet?
Nov 7, 2013 at 1:24 AM
Hi, any idea when the ApplicationOnlyAuthorizer will work for Windows Phone?
Regards, Timo
Coordinator
Nov 7, 2013 at 8:24 PM
Hi Timo,

I'm supporting it in LINQ to Twitter v3.0. More details here:

https://linqtotwitter.codeplex.com/wikipage?title=LINQ%20to%20Twitter%203.0%20Beta

Follow @JoeMayo
Nov 21, 2013 at 6:27 PM
I also had the problem with ApplicationOnlyAuthorizer in WinRT. I downloaded the source today so the version is 2.1.11.0 (from project assembly info).

Here is my test code, it's the same as seen in some examples:
     var auth = new ApplicationOnlyAuthorizer
            {
                Credentials = new InMemoryCredentials
                {
                    ConsumerKey = "xx",
                    ConsumerSecret = "yy",
                },
                UseCompression = true
            };

            auth.Authorize();
            //auth.Invalidate();
            var twitterCtx = new TwitterContext(auth);

            var srch =
                (from search in twitterCtx.Search
                 where search.Type == SearchType.Search &&
                       search.Query == "LINQ to Twitter"
                 select search)
                .SingleOrDefault();

            Debug.WriteLine("\nQuery: {0}\n", srch.SearchMetaData.Query);
            foreach (var entry in srch.Statuses)
            {
                Debug.WriteLine("ID: {0, -15}, Source: {1}\nContent: {2}\n", entry.StatusID, entry.Source, entry.Text);
            }
I figured out that the problem actually isn't in the authentication mechanism, it is working just fine. The problem lies within Authorize() method being asynchronous as it uses BeginGetRequestStream and other such methods and doesn't return Task which could be waited.

Here is a quick and dirty fix (which has only been tested like once) for the issue for those in need.
First, download the library and open project LinqToTwitterRT.
Open OAuth\ApplicationOnlyAuthorizer.cs and change the method GetBearerToken into this:
        async Task GetBearerToken()
        {
            string url = OAuth2Token;
#if SILVERLIGHT
            url = ProxyUrl + OAuth2Token;
#endif

            var req = WebRequest.Create(url) as HttpWebRequest;

            req.Method = HttpMethod.POST.ToString();
            req.Headers[HttpRequestHeader.Authorization] = "Basic " + BasicToken;
            req.ContentType = "application/x-www-form-urlencoded;charset=UTF-8";
            byte[] data = System.Text.Encoding.UTF8.GetBytes("grant_type=client_credentials");
#if !WINDOWS_PHONE && !NETFX_CORE
            req.UserAgent = UserAgent;
            req.ContentLength = data.Length;
#endif
#if !SILVERLIGHT && !NETFX_CORE
            req.Timeout = (int)Timeout.TotalMilliseconds;
#endif

            string response = null;

            using (var resetEvent = new ManualResetEvent(/*initialStateSignaled:*/ false))
            {
                Exception thrownException = null;
                using (var reqStream = await req.GetRequestStreamAsync())
                    reqStream.Write(data, 0, data.Length);
                try
                {
                    var resp = await req.GetResponseAsync();
                    response = resp.ReadReponse();
                }
                catch (Exception ex)
                {
                    thrownException = ex;
                }
                finally
                {
#if !WINDOWS_PHONE && !NETFX_CORE
                                    resetEvent.Set();
#endif
                }
#if !WINDOWS_PHONE && !NETFX_CORE
                resetEvent.WaitOne();
#endif
                if (thrownException != null) throw thrownException;

                if (response != null)
                {
                    var responseJson = JsonMapper.ToObject(response);
                    BearerToken = responseJson.GetValue<string>("access_token");
                }
            }

        }
Then add a new AuthorizeAsync method which you need to use:

        public async Task AuthorizeAsync()
        {
            this.EncodeCredentials();
            await this.GetBearerToken();
        }

Hope this helps those in trouble before the new 3.0 version is released.
  • Janne