OAuth request_token stopped working

oauth

#1

Out of no where, my twitter API calls from my ASP.NET web application, specificly my first step in the 3-legged auth, stopped working. I’ve compared the timestamps, keys and everything with the OAuth signature generator tool, and they all match (execpt oauth_nonce but thats the point I guess). Here is my code. Any suggestions or small observations would be appreciated.

protected void RequestToken()
{
        string oauthcallback = Request.Url.Host + "/TwitterCallback.aspx";
        string oauthconsumerkey = "xxx-consumerkey";
        string oauthconsumersecret = "xxx-consumerSecret";
        string oauthtokensecret = string.Empty;
        string oauthtoken = string.Empty;
        string oauthsignaturemethod = "HMAC-SHA1";
        string oauthversion = "1.0";
        string oauthnonce = Convert.ToBase64String(new ASCIIEncoding().GetBytes(DateTime.Now.Ticks.ToString()));
        TimeSpan timeSpan = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
        string oauthtimestamp = Convert.ToInt64(timeSpan.TotalSeconds).ToString();
        string url = "https://api.twitter.com/oauth/request_token?oauth_callback=" + oauthcallback;
        SortedDictionary<string, string> basestringParameters = new SortedDictionary<string, string>();
        basestringParameters.Add("oauth_version", oauthversion);
        basestringParameters.Add("oauth_consumer_key", oauthconsumerkey);
        basestringParameters.Add("oauth_nonce", oauthnonce);
        basestringParameters.Add("oauth_signature_method", oauthsignaturemethod);
        basestringParameters.Add("oauth_timestamp", oauthtimestamp);
        basestringParameters.Add("oauth_callback", Uri.EscapeDataString(oauthcallback));

        //Build the signature string
        string baseString = String.Empty;
        baseString += "POST" + "&";
        baseString += Uri.EscapeDataString(url.Split('?')[0]) + "&";
        foreach (KeyValuePair<string, string> entry in basestringParameters)
        {
            baseString += Uri.EscapeDataString(entry.Key + "=" + entry.Value + "&");
        }

        //Remove the trailing ambersand char last 3 chars - %26
        //baseString = baseString.Substring(0, baseString.Length - 3);

        //Build the signing key
        string signingKey = Uri.EscapeDataString(oauthconsumersecret) +
          "&" + Uri.EscapeDataString(oauthtokensecret);

        //Sign the request
        HMACSHA1 hasher = new HMACSHA1(new ASCIIEncoding().GetBytes(signingKey));
        string oauthsignature = Convert.ToBase64String(
          hasher.ComputeHash(new ASCIIEncoding().GetBytes(baseString)));

        //Tell Twitter we don't do the 100 continue thing
        ServicePointManager.Expect100Continue = false;
        HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(@url);

        string authorizationHeaderParams = String.Empty;
        authorizationHeaderParams += "OAuth ";
        authorizationHeaderParams += "oauth_nonce=" + "\"" +
          Uri.EscapeDataString(oauthnonce) + "\",";
        authorizationHeaderParams += "oauth_signature_method=" + "\"" +
          Uri.EscapeDataString(oauthsignaturemethod) + "\",";
        authorizationHeaderParams += "oauth_timestamp=" + "\"" +
          Uri.EscapeDataString(oauthtimestamp) + "\",";
        authorizationHeaderParams += "oauth_consumer_key=" + "\"" +
          Uri.EscapeDataString(oauthconsumerkey) + "\",";
        authorizationHeaderParams += "oauth_signature=" + "\"" +
          Uri.EscapeDataString(oauthsignature) + "\",";
        authorizationHeaderParams += "oauth_version=" + "\"" +
          Uri.EscapeDataString(oauthversion) + "\"";
        webRequest.Headers.Add("Authorization", authorizationHeaderParams);

        webRequest.Method = "POST";
        webRequest.ContentType = "application/x-www-form-urlencoded";

        //Allow us a reasonable timeout in case Twitter's busy
        webRequest.Timeout = 3 * 60 * 1000;

        try
        {
            HttpWebResponse webResponse = webRequest.GetResponse() as HttpWebResponse;
            Stream dataStream = webResponse.GetResponseStream();
            // Open the stream using a StreamReader for easy access.
            StreamReader reader = new StreamReader(dataStream);
            // Read the content.
            string responseFromServer = reader.ReadToEnd();
            var uri = new Uri("https://test.dk?" + responseFromServer);
            var token = HttpUtility.ParseQueryString(uri.Query).Get("oauth_token"); ;
            var tokensecret = HttpUtility.ParseQueryString(uri.Query).Get("oauth_token_secret");
            Response.Write(responseFromServer);
            Response.Redirect("https://api.twitter.com/oauth/authorize?force_login=true&oauth_token=" + token);
        }
        catch (Exception ex)
        {
            Response.Write(ex.GetBaseException());
        }


}

The error obviously happens when I do the HTTP request webRequest.GetResponse()

It returns a 401 unauthorized


#2

One thing to check is that the time of the system where you are running the code is good. If the time has drifted at all, it may not match up with Twitter’s end and you could end up with a bad OAuth request / unauthorized.


#3

@andypiper I’ve compared my timestamp with the one generated with the OAuth signature generator tool and it matches.
Execpt if the timestamp from the signature generator tool doesn’t reflect the time on twitters server?


#4

I’d suggest just making sure you’re synced with an NTP server or something reliable. The OAuth tool is not guaranteed to match, but should work. Have you tried the same request using e.g. twurl at the command line?

Time drift is just one of the most frequent reasons for this to happen - I might be guessing wrongly, in which case I guess we need to debug further!

You said this just stopped working - any particular point in time?


#5

@andypiper I have no experience with twurl. Actually I have no idea what it is.
No I don’t have an particular point in time. It’s a while ago. It’s on Azure some where in Europe, so it would make sense if there was a time drift i guess. Can you tell me more about twurl and how it works?


#6

I found that the token gets invalidated after getting the “This request looks like it might be automated. To protect our users from spam and other malicious activity, we can’t complete this action right now. Please try again later.” error (code #226)

After that I’ve had to get people to re authorise (which isn’t making people happy).


#7

@Twitaculous Can’t remember if I’ve ever encountered that error. Did you regenerate your OAuth keys?


#8

The app’s consumer key and secret, or the user’s access token & secret?

The only thing I’ve come up with is to get people back to my login page and get them to “sign in with twitter” again. They have to re authorise every time, even when they are regular members.


#9

@Twitaculous Consumer key and secret.

Okay. I can’t have that. A re-auth every time would ruin the purpose.


#10

I think I did. I guess doing it again wouldn’t hurt.

Yes, getting people to repeatedly reauth has been a nightmare. There’s angry people, confused people, people who think they’ve been “hacked”.

I was looking at your code:
//Allow us a reasonable timeout in case Twitter’s busy
webRequest.Timeout = 3 * 60 * 1000;
Is that 3 minutes that you are giving Twitter? You’d hope it wouldn’t take 3 minutes to repond :wink: