AccessToken en OauthToken empty on WP7

Dec 9, 2011 at 5:18 PM
Edited Dec 9, 2011 at 5:19 PM

Hi

I downloaded LinqToTwitter and I am playing around with the Windows Phone WP7 Demo.

The demo works well.  But I need to enter the PIN every time I start the application. 

I read on : http://linqtotwitter.codeplex.com/wikipage?title=Implementing%20OAuth%20for%20Desktop%20Applications that:
"After the call to authorize above, you can read the OAuthToken and AccessToken from auth.Credentials and save them in a database, associated with the current user. On subsequent queries to LINQ to Twitter, you can read those values from the database and populate the Credentials property of PinAuthorizer ahead of time. This will prevent LINQ to Twitter from re-authenticating the user and you'll be able to start making queries on behalf of that user right away."

Where do i need to put these two (oauthtoken and accesstoken) to be able to get the app automatically authorized the second time it is launched?

 

Then a second question.  I do not get the accesstoken or OAuthToken when I try to retrieve them (see code below, this is directly copy paste from the demo application execpt for the Debug.WriteLine of course)...  Is this the wrong place to get the accesstoken and oauthtoken?

Kind regards
Damiaan

 

 private void AuthenticateButton_Click(object sender, RoutedEventArgs e) {
            var settings = new AppSettings();
 
            pinAuth.CompleteAuthorize(
                PinTextBox.Text,
                completeResp => Dispatcher.BeginInvoke(() => {
                    switch (completeResp.Status) {
                        case TwitterErrorStatus.Success:
                            EventTweet.SharedState.Authorizer = pinAuth;
                            Debug.WriteLine(pinAuth.Credentials.AccessToken);
                            Debug.WriteLine(pinAuth.Credentials.OAuthToken);
                            NavigationService.GoBack();
                            break;
                        case TwitterErrorStatus.TwitterApiError:
                        [CUT]
                        
Coordinator
Dec 13, 2011 at 2:13 PM

Hi Damiaan,

I use the term database in the most general sense because L2T works on different platforms.  You can save the credentials any way you like, i.e. file, isolated storage, database, etc.  The goal is to be able to retrieve the credentials for a user, load them into the Credentials property of an authorizer (it looks like you're using PinAuthorizer here), and then instantiate TwitterContext with that authorizer.

I've seen the problem with getting the tokens from the callback before, which I fixed, and am wondering if I have a regression on that bug.  There seems to be a couple other anomalies with the Silverlight code that I need to look at too.  I'll do a work order and take this as an issue to look at.

Joe

Coordinator
Dec 13, 2011 at 2:14 PM
This discussion has been copied to a work item. Click here to go to the work item and continue the discussion.
Coordinator
Dec 14, 2011 at 2:05 AM

Hi Damiaan,

I couldn't find a bug here.  However, here's an example of how to read the tokens:

            pinAuth.CompleteAuthorize(
                PinTextBox.Text,
                completeResp => Dispatcher.BeginInvoke(() =>
                {
                    // you can save these in the db and add logic
                    // to look for credentials from db before
                    // doing Oauth dance.
                    var oauthToken = pinAuth.Credentials.OAuthToken;
                    var accessToken = pinAuth.Credentials.AccessToken;

                    switch (completeResp.Status)
                    {
                        case TwitterErrorStatus.Success:
                            SharedState.Authorizer = pinAuth;
                            NavigationService.GoBack();
                            break;
                        case TwitterErrorStatus.TwitterApiError:
                        case TwitterErrorStatus.RequestProcessingException:
                            MessageBox.Show(
                                completeResp.Error.ToString(),
                                completeResp.Message,
                                MessageBoxButton.OK);
                            break;
                    }
                }));

I'll add this to the source code solution sample on my next check-in.

Joe

Jun 23, 2012 at 8:04 PM

Thanks for the code and this example. Working with the WindowsPhoneDemo solution to get acquainted with the tool. Unfortunately your solution doesn't work as mentioned above because the pinAuth.Credentials.OAuthToken returned is incorrect. Have been looking a long time, at least I now know better how the code works, but found the solution:

If you use the code above in the WindowsPhoneDemo  in the StatusUpdate.xaml.cs, the value in the pinAuth.Credentials.OAuthToken is the token used for the request, not the token you have to use for the authorization. You can see in the code PinAuthorizer.cs, the routine Authorize() is never called if you use the Async routines for the phone BeginAuthorize() and CompleteAuthorize(). Therefore in the PinAuthorizer, the Credentials.OAuthToken, ScreenName and UserId are never updated after authorizing with the pin. 

I just made a quick hack to continue with the code but would be nice to have a better solution. I did the following:

-  Added public string OAuthToken { get; set; } to class UserIdentifier

- In OAuthTwitter.cs in GetAccessTokenAsync, added the OAuthToken to the twitterResponse.State

			finally
                        {
                            if (authenticationCompleteCallback != null)
                            {
                                twitterResponse.State =
                                    new UserIdentifier
                                    {
                                        ID = userID,
                                        UserID = userID,
                                        ScreenName = screenName,
                                        OAuthToken = this.OAuthToken
                                    };
                                authenticationCompleteCallback(twitterResponse); 
                            }
                        }

- In OAuth.xaml.cs changed the code in AuthenticateButton_Click, and saved the tokens

	private void AuthenticateButton_Click(object sender, RoutedEventArgs e)
        {
            pinAuth.CompleteAuthorize(
                PinTextBox.Text,
                completeResp => Dispatcher.BeginInvoke(() =>
                {
                    // you can save these in the db and add logic
                    // to look for credentials from db before
                    // doing Oauth dance.
 
                   // var oauthToken = pinAuth.Credentials.OAuthToken;
                   // var accessToken = pinAuth.Credentials.AccessToken;
 
                    switch (completeResp.Status)
                    {
                        case TwitterErrorStatus.Success:
                            pinAuth.UserId = completeResp.State.UserID;
                            pinAuth.ScreenName = completeResp.State.ScreenName;
                            pinAuth.Credentials.OAuthToken = completeResp.State.OAuthToken;
                            SharedState.Authorizer = pinAuth;
 
                            SavePinAuth(pinAuth);
                            NavigationService.GoBack();
                            break;
                        case TwitterErrorStatus.TwitterApiError:
                        case TwitterErrorStatus.RequestProcessingException:
                            MessageBox.Show(
                                completeResp.Error.ToString(),
                                completeResp.Message,
                                MessageBoxButton.OK);
                            break;
                    }
              
                    Debug.WriteLine(this.ToString() + "AuthenticateButton_Click, _consumerKey==>" + _consumerKey);
                    Debug.WriteLine(this.ToString() + "AuthenticateButton_Click, _consumerSecret==>" + _consumerSecret);
                    Debug.WriteLine(this.ToString() + "AuthenticateButton_Click, accessToken==>" + pinAuth.Credentials.AccessToken);
                    Debug.WriteLine(this.ToString() + "AuthenticateButton_Click, oauthToken==>" + pinAuth.Credentials.OAuthToken);
          
                }));
        }

- Now when I run the program again with saved tokens from the isolated storage it runs fine without authorization errors. 

- Note: above code is not best practice, but just a quick hack, hope you can update the code in a better more structural way to put the userid, screenname and oauthtoken in the pinAuthorizer after authorizing using the pin.

Jun 24, 2012 at 7:40 AM
Edited Jun 24, 2012 at 7:48 AM

Hi,

Forget yesterday's hack as mentioned above, was just for testing. A better solution is the following code, you only have to modify the PinAuthorizer.cs as listed below. What this change does is the following: instead of returning to the caller immediately after authorizing, instead it first will set the ScreenName, UserId and OAuthToken in the PinAuthorizer object, and thereafter return to caller. 

 	public void CompleteAuthorize(string pin, Action<TwitterAsyncResponse<UserIdentifier>> authorizationCompleteCallback)
        {
            _authorizationCompleteCallback = authorizationCompleteCallback;
 
            if (IsAuthorized) return;
 
            if (pin == null)
            {
                throw new ArgumentNullException("pin""pin is required");
            }
 
            //     OAuthTwitter.GetAccessTokenAsync(pin, new Uri(OAuthAccessTokenUrl), "oob", AuthAccessType.NoChange, authorizationCompleteCallback);
            OAuthTwitter.GetAccessTokenAsync(pin, new Uri(OAuthAccessTokenUrl), "oob"AuthAccessType.NoChange, OnCompleteAuthorize);
        }
 
        Action<TwitterAsyncResponse<UserIdentifier>> _authorizationCompleteCallback;
 
        private void OnCompleteAuthorize(TwitterAsyncResponse<UserIdentifier> twitterAsyncResponse)
        {
            ScreenName = twitterAsyncResponse.State.ScreenName;
            UserId =  twitterAsyncResponse.State.UserID;
 
            Credentials.OAuthToken = OAuthTwitter.OAuthToken;
       
            if (_authorizationCompleteCallback != null)
            {
                _authorizationCompleteCallback(twitterAsyncResponse);
            }
        }