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