Final step of the authentication flow


#1

Hi,

I’m working on a twitter .net library and I’m having a roadblock with the final step in the Authentication flow.
I’ve gotten up to the point where I have the oauth_verifier token, but when I want to exchange it I get “401 Unauthorized”. I’ve been trouble shooting this flow for almost a week now but I can’t get it to work.

I’m wondering if you guys could give me some insight and enlighten me where it might go wrong.

C# .Net Snippet - Assuming that the signatures and the request is being built correctly

private void StartAuthenticationFlow()
{
    // Make a twitter request to start the Authentication Flow
    TwitterAPI api = new TwitterAPI(
        new TwitterAPIContext()
        {
            oauth_consumer_key = MDIParent.CONSUMER_KEY,
            oauth_consumer_secret = MDIParent.CONSUMER_SECRET
        });

    RequestDesign design = api.RequestFactory.DesignBuilder(RequestType.PostRequestToken,
        new DesignParam("oauth_token", MDIParent.RequestTokenCallbackURL));

    string result;

    result = api.ExecuteDesign(design).ToString();

    Dictionary<string, string> dict_v = ParseVars(result);            

    // Redirect the user to the twitter page for authorization:
    Browser.Navigate(string.Format("https://api.twitter.com/oauth/authorize?oauth_token={0}&force_login", dict_v["oauth_token"]));
}


private void Browser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
    string document = Browser.DocumentText;

    if (Browser.Url.ToString().IndexOf("oauth_request_token_callback.php") != -1)
    {
        // ====>  Inside twitter redirected callback 

        Browser.DocumentText = "Processing...";

        // Find and extract the var string from the webpage source: which is of format V:={BASE64_ENCODED_LIST}
        int i, j, l;
        i = document.IndexOf("V:={") + 4;
        j = document.IndexOf("}", i);
        l = j - i;

        string varstring = SharedMembers.Base64Decode(document.Substring(i, l));

        // Turn these vars into a dictionary:
        Dictionary<string, string> dict_v = ParseVars(varstring);

        // Make a new request to twitter to exchange access tokens:
        TwitterAPI api = new TwitterAPI(
            new TwitterAPIContext()
            {
                oauth_consumer_key = MDIParent.CONSUMER_KEY,
                oauth_consumer_secret = MDIParent.CONSUMER_SECRET
            });

        DesignParam oauth_verifier = new DesignParam("oauth_verifier", dict_v["oauth_verifier"]);
        //DesignParam oauth_token = new DesignParam("oauth_token", dict_v["oauth_token"]);
        RequestDesign design = api.RequestFactory.DesignBuilder(RequestType.PostOAuthAccessToken, oauth_verifier);

        string result = api.ExecuteDesign(design).ToString();
        
        // Extract the user's access tokens and save it into a dictionary:
        dict_v = ParseVars(result);

        // Finally add the new twitter account to the account manager:
        host.AddTwitterAccount(dict_v["screen_name"], long.Parse(dict_v["user_id"]), dict_v["oauth_token"], dict_v["oauth_token_secret"]);

        btnOk_Click(null, null); // Exit this form.
    }
}

A quick explaination of the types used here.

TwitterAPI - The core library to interact with the Twitter REST or Streaming API.

TwitterAPIContext - The context in which the library should run. This type has just 4 members:
- string oauth_consumer_key
- string oauth_consumer_secret
- string oauth_user_token (Null or string.Empty if unknown)
- string oauth_user_token_secret (Null or string.Emty if unknown)

DesignParam - This is used to add additional parameters to a request.

RequestDesign - This type describes the data package to be send to twitter such as the http-method, the url, the http body and headers. RequestFactory.DesignBuilder() generates the design, when it has finished, the design is then past to ExecuteDesign() which opens an web socket to twitter and transports the data within the design.

MDIParent - Just the main application. “host” is an instance of this type.

Data log

[29/09/2013 21:32:57]
= Design =
  URI: https://api.twitter.com/oauth/request_token
  Http Method: POST
  Type: PostRequestToken
  AuthHeader: OAuth oauth_consumer_key="4LOdMfjg9BZPECVkA8ENMg", oauth_nonce="NjM1MTYwODcxNzc4ODk3MDA2", oauth_signature="%2BWq8%2BhHGbru0PjLdHJT0qfs65qE%3D", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1380483178", oauth_version="1.0"
  Body: oauth_token=http%3A%2F%2Flemonjuice.mcodev.org%2Foauth_request_token_callback.php

[29/09/2013 21:32:58]
IN:> (System.String) ** DUMP **
0001   6f 61 75 74 68 5f 74 6f 6b 65 6e 3d 4f 72 47 78   oauth_token=OrGx
0002   67 6e 6a 43 58 4b 79 71 56 4b 53 70 4e 46 6f 77   gnjCXKyqVKSpNFow
0003   49 76 68 31 35 4d 43 4e 77 34 35 34 76 43 43 4d   Ivh15MCNw454vCCM
0004   48 4a 46 67 69 38 26 6f 61 75 74 68 5f 74 6f 6b   HJFgi8&oauth_tok
0005   65 6e 5f 73 65 63 72 65 74 3d 00 00 00 00 00 00   en_secret=......
0006   00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................
0007   00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................
0008   00 00 00 00 26 6f 61 75 74 68 5f 63 61 6c 6c 62   ....&oauth_callb
0009   61 63 6b 5f 63 6f 6e 66 69 72 6d 65 64 3d 74 72   ack_confirmed=tr
0010   75 65                                             ue

[29/09/2013 21:33:12]
= Design =
  URI: https://api.twitter.com/oauth/access_token
  Http Method: POST
  Type: PostOAuthAccessToken
  AuthHeader: OAuth oauth_consumer_key="4LOdMfjg9BZPECVkA8ENMg", oauth_nonce="NjM1MTYwODcxODk2ODA4MzMw", oauth_signature="omLJL5WUlPCYlOQ5MnvIHF4ovYA%3D", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1380483190", oauth_version="1.0"
  Body: oauth_verifier=YXhedsveJ9nl6izOg4k7KesLcJigMOjqrB1AvTU

[29/09/2013 21:33:12]
(Exception) The remote server returned an error: (401) Unauthorized.:
   at System.Net.HttpWebRequest.GetResponse()
   at Juice.TwitterAPI.ExecuteDesign(RequestDesign request) in \Juice\TwitterAPI.cs:line 255

#2

It looks like on the oauth/access_token step you might not be sending your oauth_token value (the request token you’re exchanging for an access token). It should be part of this request step, along with the oauth_verifier.


#3

my goodness. I was sooo close. I even commented that line out. I probably forgot to add that param to the DesignBuilder in frustration when I tested that. Silly me!

Thanks!

DesignParam oauth_verifier = new DesignParam("oauth_verifier", dict_v["oauth_verifier"]); DesignParam oauth_token = new DesignParam("oauth_token", dict_v["oauth_token"]); RequestDesign design = api.RequestFactory.DesignBuilder(RequestType.PostOAuthAccessToken, oauth_verifier, oauth_token);