Developing SevenDrops - A Dropbox-based photo uploader for Windows Phone 7 [4/6]
Join the DZone community and get the full member experience.
Join For FreeTime to get further with OAuth, and now it gets a little bit more complicated because we'll have to deal with request signing (which might be a headache for some beginners). As I showed in my previous article, we already have the token and the secret needed to perform the required manipulations.
I try to generally avoid parameter-based OAuth flow, so I will be building an OAuth header. The first method I am going to perform experiments is the one that retrieves profile information and it is represented by the following endpoint:
https://api.dropbox.com/<version>/account/info
Where once again, the version is currently is set to 0 but is subject to change at any time the Dropbox system gets an update.
Let's look at the set of parameters needed to perform the OAuth request
- oauth_token
- oauth_consumer_key
- oauth_signature
- oauth_signature_method
- oauth_timestamp
- oauth_nonce
- oauth_version
oauth_consumer_key is obviously the key assigned to your application by Dropbox but the rest aren't really helpful here. oauth_token is the token you obtained in exchange for the entered user credentials, so there is not going to be a problem in obtaning it.
oauth_timestamp is the current UNIX timestamp and it should be the current time. Otherwise, the request will be rejected. It can be easily generated by using this heler static class:
public static class CurrentUNIXTimestamp { public static string Get() { return Convert.ToString((int)(DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds); } }
oauth_nonce in my case will be a simpel GUID. It is generally not advisable to use it due to the possibility of collision issues later on, but it is enough for testing purposes:
Guid.NewGuid().ToString().Replace("-", "")
oauth_version is constantly set to 1.0 - this is defined by the OAuth specifications and shouldn't be changed by any means.
Time to look at the signature. Since it is only used in the OAuth header itself, I decided that I need to generate the OAuth header itself in a separate method, the signature being automatically included there. I added an OAuth folder to the project and created an OAuthClient static class that will help me perform some data manipulations:
So the class itself, with the OAuth header generating method looks like this:
public static class OAuthClient { public static string GetOAuthHeader(Dictionary<string, string> parameters, string httpMethod, string url, string consumerSecret, string tokenSecret) { parameters = parameters.OrderBy(x => x.Key).ToDictionary(v => v.Key, v => v.Value); string concat = string.Empty; string OAuthHeader = "OAuth "; foreach (string k in parameters.Keys) { concat += k + "=" + parameters[k] + "&"; OAuthHeader += k + "=" + "\"" + parameters[k] + "\", "; } concat = concat.Remove(concat.Length - 1, 1); concat = StringHelper.EncodeToUpper(concat); concat = httpMethod + "&" + StringHelper.EncodeToUpper(url) + "&" + concat; byte[] content = Encoding.UTF8.GetBytes(concat); HMACSHA1 hmac = new HMACSHA1(Encoding.UTF8.GetBytes(consumerSecret + "&" + tokenSecret)); hmac.ComputeHash(content); string hash = Convert.ToBase64String(hmac.Hash); hash = hash.Replace("-", ""); OAuthHeader += "oauth_signature=\"" + StringHelper.EncodeToUpper(hash) + "\""; return OAuthHeader; } }
For the GetOAuthHeader method I followed the standard pattern:
1. Arrange the parameters alphabetically (that's what OrderBy does in my case).
2. Concatenate parameters (I am building the OAuth header at the same time, as shown by the OAuthHeader string). Keys are separated from values by the equal (=) sign and each pair is separated from another by an and (&) sign.
3. Append the HTTP method used to the beginning of the concatenated parameter list, as well as the base URL where the request is directed. The pattern goes as this: METHOD&URL&CONCATENATED_STRING. Notice that both the method and the URL are separated by an unencoded and (&) sign - the rest MUST be URL-encoded.
4. Encode the base string. HMAC-SHA1 is the only supported signature method and it can be invoked via the HMACSHA1 class.
5. Append the encoded string to the OAuth header.
You probably noticed that I am also calling StringHelper.EncodeToUpper. This is a method I described in my recent . It is related to the way HttpUtility.UrlEncode works, returning lowercase characters instead of uppercase (like it should), therefore messing with the signature.
The method looks like this:
public static string EncodeToUpper(string raw) { raw = HttpUtility.UrlEncode(raw); return Regex.Replace(raw, "(%[0-9a-f][0-9a-f])", c => c.Value.ToUpper()); }
Now you have the core OAuth mechanism ready. All that needs to be done now is create actually invoke needed methods via HttpWebRequest.
Opinions expressed by DZone contributors are their own.
Comments