Skip to content

Instantly share code, notes, and snippets.

@SeanHayes
Created July 3, 2010 01:21
Show Gist options
  • Save SeanHayes/462169 to your computer and use it in GitHub Desktop.
Save SeanHayes/462169 to your computer and use it in GitHub Desktop.
Pseudo code for signing OAuth requests
function urlEncode(str){
//everything except [a-zA-Z0-9-_~.] must be percent encoded: http://tools.ietf.org/html/rfc5849#section-3.6
}
function hmac_sha1(key, text){
//you'll definitely want a library for this. I used Crypto-JS: http://code.google.com/p/crypto-js/
}
function base64me(key, text){
//I used Crypto-JS for this too.
}
/*
httpMethod - string
url - string
params - key/value array
*/
//assume 'GET', 'http://seanhayes.name/', and {foo: ['baz', 'blah'], bar: 'true'} is passed in
function signRequest(httpMethod, url, params){
var signature = [];//new, empty array
params.sort();//sort by key name in alphabetical order. if duplicate keys, sort those by same method.
//first, generate param section of unhashed signature
foreach(params as key, value){
//code for detecting whether 'value' is itself an array and iterating through it has been left out
signature.append(urlEncode(key)+'='+urlEncode(value));
}
signature = signature.join('&')
//we now have 'foo=baz&foo=blah&bar=true'
//each component gets URL encoded. Yes, even the params part gets URL encoded, AGAIN
signature = httpMethod.toUpperCase()+'&'+urlEncode(url)+'&'+urlEncode(signature);
//we now have 'GET&http%3A%2F%2Fseanhayes.name%2F&foo%3Dbaz%26foo%3Dblah%26bar%3Dtrue'
/*
oauth_consumer_secret and oauth_token_secret should be in a namespace accessible to this function
For the purposes of this example, oauth_consumer_secret equals 'anonymous'. When starting the authentication process, oauth_token_secret will be an empty string (''). It will change to some other value given to you by the OAuth provider once your token is authorized.
*/
var key = urlEncode(oauth_consumer_secret)+'&'+urlEncode(oauth_token_secret);
//we'll be using the HMAC-SHA1 encryption method, since it allows anonymous applications to connect (at least with Google)
signature = hmac_sha1(key, signature);
//Then base64 encode it all. Yes, this should make all the previous URL encoding completely unneccessary, but this is what the spec says.
signature = base64me(signature);
/*
I used Crypto-JS, which involves the following:
signature = Crypto.HMAC(Crypto.SHA1, signature, key);
signature = Crypto.util.hexToBytes(signature)
signature = Crypto.util.bytesToBase64(signature);
*/
//You now have a signature in base64 format.
//Don't forget to URL encode this before transmitting (base64 text can contain +, /, and =); I left it out here since all the params will probably get url encoded later when the HTTP message is constructed. Yes, this should make the previous base64 encoding completely unneccessary, but this is what the spec says. (I guess maybe it saves more space than all the binary values getting converted to %xx.)
return signature;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment