Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Getting the request_token to work (Twitter API)

DZone's Guide to

Getting the request_token to work (Twitter API)

·
Free Resource

Not long ago Twitter finally switched completely to OAuth, completely eliminating basic authentication. As OAuth is more secure, it also carries some implementation problems that are especially visible to beginner users. In this article I am not going to go in detail about the specifics of OAuth itself (since it's a topic on its own - for more information, read here) but rather about the implementation of the OAuth-based mechanism related to the request_token method in the Twitter API.

Let's first see what parameters are required for the token. The Twitter API documentation isn't really specific about this, however there is a note here that covers the requirements. So here are the parameters used:

  • oauth_consumer_key
  • oauth_signature_method
  • oauth_timestamp
  • oauth_nonce
  • oauth_version

The consumer key is given to you once you register your application. It is also known as the API key. The signature method should be set manually to HMAC-SHA1 (just like that - a string). It is the only accepted method and even though some services that rely on OAuth authentication flow also accept PLAINTEXT (non-encoded string), Twitter will return a 401 Unauthorized in case a non-HMAC-SHA1 signature will be passed.

Now for the interesting part - timestamp. This is also the most problematic part, since an invalid timestamp causes yet another 401 Unauthorized. In my case, I was trying to analyze the entire signature pattern when the timestamp was off one day.

In my case, I ended up using this snippet to generate the proper value:

public static class CurrentUNIXTimestamp
{
    public static string Get()
    {
        return Convert.ToString((int)(DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds);
    }
}

UtcNow is required here.

The nonce is the unique identifier for the session. In my case, I am going the simple way to test out the capabilities and using a GUID that has the dashes removed. For security reasons this is not the best choice because it can easily be repeated and the session compromised. But for testing purposes it's enough. Like this:

Guid.NewGuid().ToString().Replace("-", "")

The version is constant and currently should be set to 1.0 (also as a string value).

In order to get all parameters together, I used a Dictionary instance and added each needed OAuth parameter there:

Dictionary<string, string> parameters = new Dictionary<string, string>();

parameters.Add("oauth_consumer_key", Twitter.ConsumerKey);
parameters.Add("oauth_signature_method", Twitter.SignatureMethod);
parameters.Add("oauth_timestamp", CurrentUNIXTimestamp.Get());
parameters.Add("oauth_nonce", Guid.NewGuid().ToString().Replace("-", ""));
parameters.Add("oauth_version", "1.0");

Here I am also referencing a static Twitter class that has some constant values, like ConsumerKey and SignatureMethod. So far, this is everything that's needed parameter-wise.

Now it's time to arrange the parameters based on their name. Given that there is no default Arrange method for generic collections, there is a small "trick":

parameters = parameters.OrderBy(x => x.Key).ToDictionary(v => v.Key, v => v.Value);

When creating the signature, the parameters must be ordered. Also, all parameters should be concatenated in a single string.

string OAuthHeader = "OAuth ";
foreach (string k in parameters.Keys)
{
if (k == "oauth_callback")
{
concat += k + "=" + EncodeToUpper(parameters[k]) + "&";
OAuthHeader += k + "=" + "\"" + EncodeToUpper(parameters[k]) + "\", ";
}
else
{
concat += k + "=" + parameters[k] + "&";
OAuthHeader += k + "=" + "\"" + parameters[k] + "\", ";
}

}

Notice that I am also composing the OAuth authorization header. It is recommended to use the header instead of the parameter-based auth for easier manipulation and testing. Also, that way you will avoid the need to directly encode all parameters passed in the URL directly.

Due to the way I concatenate strings, the ending will be a & symbol. I need to eliminate it:

concat = concat.Remove(concat.Length - 1, 1);

Here, the oauth_callback is never used, but when it is - it should be encoded twice. Here you see that I call the EncodeToUpper method. It was described in this post on StackOverflow. The problem lies in the fact that the default HttpUtility.UrlEncode method returns lowercase characters. For example, '=' (the equal sign) will be replaced with '%3d' - this might be a problem, especially when the SHA hash will be generated, as this will cause the signature to be invalid (containing characters that are not expected). To avoid this, all characters after the % sign should be uppercase.

public string EncodeToUpper(string raw)
{
    raw = HttpUtility.UrlEncode(raw);
    return Regex.Replace(raw, "(%[0-9a-f][0-9a-f])", c => c.Value.ToUpper());
}

The base signature string should also contain the method (in this case POST) concatenated with the URL (to request the token for this situation) - the URL should be encoded, but should be delimited from the method and the rest of the signature with an unencoded & sign:

concat = "POST&" + EncodeToUpper(Twitter.RequestTokenURL) + "&" + concat;

That's the same concatenated string from above with extra content at the beginning. The signature is generated via the HMACSHA1 class, but the base string should be converted to a byte array first.

byte[] content = Encoding.UTF8.GetBytes(concat);

HMACSHA1 hmac = new HMACSHA1(Encoding.ASCII.GetBytes(Twitter.ConsumerSecret + "&"));
hmac.ComputeHash(content);

string hash = Convert.ToBase64String(hmac.Hash);
hash = hash.Replace("-", "");

Notice that I am using the consumer secret, as well as the & sign as the key here. If there would be a token, I would pass it as well after the and sign, but since there is nothing, I am not using it.

The OAuthHeader string already contains the necessary data (I created it above), so all that needs to be done is add the newly created signature:

OAuthHeader += "oauth_signature=\"" + EncodeToUpper(hash) + "\"";

I can now create the HttpWebRequest with the data I have:

HttpWebRequest request = (HttpWebRequest)WebRequest.Create(Twitter.RequestTokenURL);
request.Method = "POST";
request.Headers["Authorization"] = OAuthHeader;

It is possible to get the response and get the token and the token secret now.

HttpWebResponse resp = (HttpWebResponse)request.GetResponse();
using (StreamReader reader = new StreamReader(resp.GetResponseStream()))
{
    string a = reader.ReadToEnd();
    Debug.WriteLine(a);
}

It is returned as JSON-formatted data, so you will have to parse it out for further use.

Topics:

Opinions expressed by DZone contributors are their own.

THE DZONE NEWSLETTER

Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

X

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}