├── oauthTest.html ├── README.txt ├── example ├── index.html ├── authorize.html ├── requestToken.html ├── accessToken.html ├── echo.html ├── AJAX.html ├── consumer.js ├── signature.html └── gadget │ └── oauth-example.xml ├── sha1.js ├── oauthTest.js └── oauth.js /oauthTest.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 |
10 |
11 |
12 | 13 | 14 | -------------------------------------------------------------------------------- /README.txt: -------------------------------------------------------------------------------- 1 | This is JavaScript software for implementing an OAuth consumer. 2 | 3 | Authors: 4 | John Kristian 5 | 6 | IMPORTANT NOTE 7 | ============== 8 | This library isn't as useful as you think it's going to be. 9 | 10 | OAuth is based around allowing tools and websites to talk to each other. 11 | However, JavaScript running in web browsers is nearly always hampered by 12 | security restrictions which prevent code running on one website from 13 | accessing data stored or served on another. 14 | 15 | Before you start hacking, make sure you understand the limitations posed 16 | by cross-domain XMLHttpRequest. 17 | 18 | WITH THAT SAID... 19 | ================= 20 | There are an increasing number of platforms which use JavaScript as 21 | their language, but enable the programmer to access remote sites. 22 | Examples include Google Gadgets, and Microsoft Vista Sidebar. For those 23 | platforms, this library should come in handy. 24 | -------------------------------------------------------------------------------- /example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Here's a small demonstration of the 4 | OAuth library for JavaScript. 5 | You can fill out a form to 6 | get a request token. 7 | Then copy and paste the token into the form to 8 | authorize your consumer. 9 | Then copy and paste the token and secret into the form to 10 | get an access token. 11 | Then copy and paste the access token and secret into the form to 12 | echo a message. 13 |

14 | When using Microsoft Internet Explorer, you can prevent annoying warnings 15 | about protecting your security by going to 16 | 'Tools > Internet Options ... > Advanced > Security' 17 | and checking the box 18 | 'Allow active content to run in files on my computer'. 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /example/authorize.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |

7 |
8 | request token:
9 | callback URL: 10 |
11 |
12 | Service provider: 13 |
18 | URL:
19 |
20 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /example/requestToken.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 |
10 | consumer key:
11 | signature method: 12 | 13 | 14 | 15 |
16 |
17 | Service provider: 18 |
24 | URL:
25 | consumer secret:
26 | 27 |
28 | 29 | 30 | -------------------------------------------------------------------------------- /example/accessToken.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 |
10 | consumer key:
11 | request token:
12 | signature method: 13 | 14 | 15 | 16 |
17 |
18 | Service provider: 19 |
25 | URL:
26 | consumer secret:
27 | token secret: 28 |
29 | 30 | 31 | -------------------------------------------------------------------------------- /example/echo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 |
10 | message:
11 | option 1
12 | option 2
13 | consumer key:
14 | access token:
15 | signature method: 16 | 17 | 18 | 19 |
20 |
21 | Service provider: 22 |
28 | URL:
29 | consumer secret:
30 | token secret: 31 |
32 | 33 | 34 | -------------------------------------------------------------------------------- /example/AJAX.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Here's a very simple example of using 4 | OAuth via 5 | XMLHttpRequest. 6 | Each of these buttons will request OAuth tokens, 7 | and display the resulting HTTP responses in popup windows. 8 |

9 | 10 | 11 | 12 |

13 | This won't work if you load this page from an HTTP server, because 14 | it attempts to send requests via XMLHttpRequest to term.ie or madgex.com. 15 | Most browsers forbid this for 16 | security reasons. 17 | You can make it work with Microsoft Internet Explorer, if you 18 | copy this page to a file and direct your browser to load from the file. 19 | 20 | 21 | 22 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /example/consumer.js: -------------------------------------------------------------------------------- 1 | var consumer = {}; 2 | 3 | consumer.example = 4 | { consumerKey : "myKey" 5 | , consumerSecret: "mySecret" 6 | , serviceProvider: 7 | { signatureMethod : "HMAC-SHA1" 8 | , requestTokenURL : "http://localhost/oauth-provider/request_token" 9 | , userAuthorizationURL: "http://localhost/oauth-provider/authorize" 10 | , accessTokenURL : "http://localhost/oauth-provider/access_token" 11 | , echoURL : "http://localhost/oauth-provider/echo" 12 | } 13 | }; 14 | 15 | consumer.madgex = 16 | { consumerKey : "key" 17 | , consumerSecret: "secret" 18 | , accessToken: "requestkey" 19 | , accessTokenSecret: "requestsecret" 20 | , echo: "accesskey" 21 | , echoSecret: "accesssecret" 22 | , serviceProvider: 23 | { signatureMethod : "HMAC-SHA1" 24 | , requestTokenURL : "http://echo.lab.madgex.com/request-token.ashx" 25 | , accessTokenURL : "http://echo.lab.madgex.com/access-token.ashx" 26 | , echoURL : "http://echo.lab.madgex.com/echo.ashx" 27 | } 28 | }; 29 | 30 | consumer.mediamatic = 31 | { consumerKey : "e388e4f4d6f4cc10ff6dc0fd1637da370478e49e2" 32 | , consumerSecret: "0b062293b6e29ec91a23b2002abf88e9" 33 | , serviceProvider: 34 | { signatureMethod : "HMAC-SHA1" 35 | , requestTokenURL : "http://oauth-sandbox.mediamatic.nl/module/OAuth/request_token" 36 | , userAuthorizationURL: "http://oauth-sandbox.mediamatic.nl/module/OAuth/authorize" 37 | , accessTokenURL : "http://oauth-sandbox.mediamatic.nl/module/OAuth/access_token" 38 | , echoURL : "http://oauth-sandbox.mediamatic.nl/services/rest/?method=anymeta.test.echo" 39 | } 40 | }; 41 | 42 | consumer.termie = 43 | { consumerKey : "key" 44 | , consumerSecret: "secret" 45 | , accessToken: "requestkey" 46 | , accessTokenSecret: "requestsecret" 47 | , echo: "accesskey" 48 | , echoSecret: "accesssecret" 49 | , serviceProvider: 50 | { signatureMethod : "HMAC-SHA1" 51 | , requestTokenURL : "http://term.ie/oauth/example/request_token.php" 52 | , userAuthorizationURL: "accessToken.html" // a stub 53 | , accessTokenURL : "http://term.ie/oauth/example/access_token.php" 54 | , echoURL : "http://term.ie/oauth/example/echo_api.php" 55 | } 56 | }; 57 | 58 | consumer.initializeForm = 59 | function initializeForm(form, etc, usage) { 60 | var selector = etc.elements[0]; 61 | var selection = selector.options[selector.selectedIndex].value; 62 | var selected = consumer[selection]; 63 | if (selected != null) { 64 | consumer.setInputs(etc, { URL : selected.serviceProvider[usage + "URL"] 65 | , consumerSecret: selected.consumerSecret 66 | , tokenSecret : selected[usage + "Secret"] 67 | }); 68 | consumer.setInputs(form, { oauth_signature_method: selected.serviceProvider.signatureMethod 69 | , oauth_consumer_key : selected.consumerKey 70 | , oauth_token : selected[usage] 71 | }); 72 | } 73 | return true; 74 | }; 75 | 76 | consumer.setInputs = 77 | function setInputs(form, props) { 78 | for (p in props) { 79 | if (form[p] != null && props[p] != null) { 80 | form[p].value = props[p]; 81 | } 82 | } 83 | } 84 | 85 | consumer.signForm = 86 | function signForm(form, etc) { 87 | form.action = etc.URL.value; 88 | var accessor = { consumerSecret: etc.consumerSecret.value 89 | , tokenSecret : etc.tokenSecret.value}; 90 | var message = { action: form.action 91 | , method: form.method 92 | , parameters: [] 93 | }; 94 | for (var e = 0; e < form.elements.length; ++e) { 95 | var input = form.elements[e]; 96 | if (input.name != null && input.name != "" && input.value != null 97 | && (!(input.type == "checkbox" || input.type == "radio") || input.checked)) 98 | { 99 | message.parameters.push([input.name, input.value]); 100 | } 101 | } 102 | OAuth.setTimestampAndNonce(message); 103 | OAuth.SignatureMethod.sign(message, accessor); 104 | //alert(outline("message", message)); 105 | var parameterMap = OAuth.getParameterMap(message.parameters); 106 | for (var p in parameterMap) { 107 | if (p.substring(0, 6) == "oauth_" 108 | && form[p] != null && form[p].name != null && form[p].name != "") 109 | { 110 | form[p].value = parameterMap[p]; 111 | } 112 | } 113 | return true; 114 | }; 115 | -------------------------------------------------------------------------------- /example/signature.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 45 | 46 | 47 | To compute an 48 | OAuth 49 | request signature, 50 | fill in this form and click the 'Sign' button. 51 |

52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 63 | 65 | 66 |
HTTP method:
URL:
parameters:
version:
consumer key:
consumer secret:
token:
token secret:
timestamp: 62 |
nonce: 64 |
signature method:
67 | 68 | 69 |
70 | 71 | 72 | 73 | 74 | 75 |
normalized parameters:
 
signature base string:
  
signature:
            
Authorization header:
  
76 |
77 | 78 | 79 | -------------------------------------------------------------------------------- /example/gadget/oauth-example.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 15 | 16 | 17 | 19 | 20 | 21 | 22 |
23 |
24 |
25 |
26 |
27 | 119 | ]]> 120 |
121 |
122 | -------------------------------------------------------------------------------- /sha1.js: -------------------------------------------------------------------------------- 1 | /* 2 | * A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined 3 | * in FIPS PUB 180-1 4 | * Version 2.1a Copyright Paul Johnston 2000 - 2002. 5 | * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet 6 | * Distributed under the BSD License 7 | * See http://pajhome.org.uk/crypt/md5 for details. 8 | */ 9 | 10 | /* 11 | * Configurable variables. You may need to tweak these to be compatible with 12 | * the server-side, but the defaults work in most cases. 13 | */ 14 | var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */ 15 | var b64pad = ""; /* base-64 pad character. "=" for strict RFC compliance */ 16 | var chrsz = 8; /* bits per input character. 8 - ASCII; 16 - Unicode */ 17 | 18 | /* 19 | * These are the functions you'll usually want to call 20 | * They take string arguments and return either hex or base-64 encoded strings 21 | */ 22 | function hex_sha1(s){return binb2hex(core_sha1(str2binb(s),s.length * chrsz));} 23 | function b64_sha1(s){return binb2b64(core_sha1(str2binb(s),s.length * chrsz));} 24 | function str_sha1(s){return binb2str(core_sha1(str2binb(s),s.length * chrsz));} 25 | function hex_hmac_sha1(key, data){ return binb2hex(core_hmac_sha1(key, data));} 26 | function b64_hmac_sha1(key, data){ return binb2b64(core_hmac_sha1(key, data));} 27 | function str_hmac_sha1(key, data){ return binb2str(core_hmac_sha1(key, data));} 28 | 29 | /* 30 | * Perform a simple self-test to see if the VM is working 31 | */ 32 | function sha1_vm_test() 33 | { 34 | return hex_sha1("abc") == "a9993e364706816aba3e25717850c26c9cd0d89d"; 35 | } 36 | 37 | /* 38 | * Calculate the SHA-1 of an array of big-endian words, and a bit length 39 | */ 40 | function core_sha1(x, len) 41 | { 42 | /* append padding */ 43 | x[len >> 5] |= 0x80 << (24 - len % 32); 44 | x[((len + 64 >> 9) << 4) + 15] = len; 45 | 46 | var w = Array(80); 47 | var a = 1732584193; 48 | var b = -271733879; 49 | var c = -1732584194; 50 | var d = 271733878; 51 | var e = -1009589776; 52 | 53 | for(var i = 0; i < x.length; i += 16) 54 | { 55 | var olda = a; 56 | var oldb = b; 57 | var oldc = c; 58 | var oldd = d; 59 | var olde = e; 60 | 61 | for(var j = 0; j < 80; j++) 62 | { 63 | if(j < 16) w[j] = x[i + j]; 64 | else w[j] = rol(w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16], 1); 65 | var t = safe_add(safe_add(rol(a, 5), sha1_ft(j, b, c, d)), 66 | safe_add(safe_add(e, w[j]), sha1_kt(j))); 67 | e = d; 68 | d = c; 69 | c = rol(b, 30); 70 | b = a; 71 | a = t; 72 | } 73 | 74 | a = safe_add(a, olda); 75 | b = safe_add(b, oldb); 76 | c = safe_add(c, oldc); 77 | d = safe_add(d, oldd); 78 | e = safe_add(e, olde); 79 | } 80 | return Array(a, b, c, d, e); 81 | 82 | } 83 | 84 | /* 85 | * Perform the appropriate triplet combination function for the current 86 | * iteration 87 | */ 88 | function sha1_ft(t, b, c, d) 89 | { 90 | if(t < 20) return (b & c) | ((~b) & d); 91 | if(t < 40) return b ^ c ^ d; 92 | if(t < 60) return (b & c) | (b & d) | (c & d); 93 | return b ^ c ^ d; 94 | } 95 | 96 | /* 97 | * Determine the appropriate additive constant for the current iteration 98 | */ 99 | function sha1_kt(t) 100 | { 101 | return (t < 20) ? 1518500249 : (t < 40) ? 1859775393 : 102 | (t < 60) ? -1894007588 : -899497514; 103 | } 104 | 105 | /* 106 | * Calculate the HMAC-SHA1 of a key and some data 107 | */ 108 | function core_hmac_sha1(key, data) 109 | { 110 | var bkey = str2binb(key); 111 | if(bkey.length > 16) bkey = core_sha1(bkey, key.length * chrsz); 112 | 113 | var ipad = Array(16), opad = Array(16); 114 | for(var i = 0; i < 16; i++) 115 | { 116 | ipad[i] = bkey[i] ^ 0x36363636; 117 | opad[i] = bkey[i] ^ 0x5C5C5C5C; 118 | } 119 | 120 | var hash = core_sha1(ipad.concat(str2binb(data)), 512 + data.length * chrsz); 121 | return core_sha1(opad.concat(hash), 512 + 160); 122 | } 123 | 124 | /* 125 | * Add integers, wrapping at 2^32. This uses 16-bit operations internally 126 | * to work around bugs in some JS interpreters. 127 | */ 128 | function safe_add(x, y) 129 | { 130 | var lsw = (x & 0xFFFF) + (y & 0xFFFF); 131 | var msw = (x >> 16) + (y >> 16) + (lsw >> 16); 132 | return (msw << 16) | (lsw & 0xFFFF); 133 | } 134 | 135 | /* 136 | * Bitwise rotate a 32-bit number to the left. 137 | */ 138 | function rol(num, cnt) 139 | { 140 | return (num << cnt) | (num >>> (32 - cnt)); 141 | } 142 | 143 | /* 144 | * Convert an 8-bit or 16-bit string to an array of big-endian words 145 | * In 8-bit function, characters >255 have their hi-byte silently ignored. 146 | */ 147 | function str2binb(str) 148 | { 149 | var bin = Array(); 150 | var mask = (1 << chrsz) - 1; 151 | for(var i = 0; i < str.length * chrsz; i += chrsz) 152 | bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (32 - chrsz - i%32); 153 | return bin; 154 | } 155 | 156 | /* 157 | * Convert an array of big-endian words to a string 158 | */ 159 | function binb2str(bin) 160 | { 161 | var str = ""; 162 | var mask = (1 << chrsz) - 1; 163 | for(var i = 0; i < bin.length * 32; i += chrsz) 164 | str += String.fromCharCode((bin[i>>5] >>> (32 - chrsz - i%32)) & mask); 165 | return str; 166 | } 167 | 168 | /* 169 | * Convert an array of big-endian words to a hex string. 170 | */ 171 | function binb2hex(binarray) 172 | { 173 | var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef"; 174 | var str = ""; 175 | for(var i = 0; i < binarray.length * 4; i++) 176 | { 177 | str += hex_tab.charAt((binarray[i>>2] >> ((3 - i%4)*8+4)) & 0xF) + 178 | hex_tab.charAt((binarray[i>>2] >> ((3 - i%4)*8 )) & 0xF); 179 | } 180 | return str; 181 | } 182 | 183 | /* 184 | * Convert an array of big-endian words to a base-64 string 185 | */ 186 | function binb2b64(binarray) 187 | { 188 | var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 189 | var str = ""; 190 | for(var i = 0; i < binarray.length * 4; i += 3) 191 | { 192 | var triplet = (((binarray[i >> 2] >> 8 * (3 - i %4)) & 0xFF) << 16) 193 | | (((binarray[i+1 >> 2] >> 8 * (3 - (i+1)%4)) & 0xFF) << 8 ) 194 | | ((binarray[i+2 >> 2] >> 8 * (3 - (i+2)%4)) & 0xFF); 195 | for(var j = 0; j < 4; j++) 196 | { 197 | if(i * 8 + j * 6 > binarray.length * 32) str += b64pad; 198 | else str += tab.charAt((triplet >> 6*(3-j)) & 0x3F); 199 | } 200 | } 201 | return str; 202 | } 203 | -------------------------------------------------------------------------------- /oauthTest.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2008 Netflix, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | // Here are some unit tests for the software in oauth.js. 18 | // The test data were copied from http://oauth.pbwiki.com/TestCases 19 | 20 | function testOAuth() { 21 | testEncode(); 22 | testGetParameters(); 23 | testGetBaseString(); 24 | testGetSignature(); 25 | } 26 | 27 | var ENCODING // From http://wiki.oauth.net/TestCases 28 | = [ ["abcABC123", "abcABC123"] 29 | , ["-._~" , "-._~"] 30 | , ["%" , "%25"] 31 | , ["+" , "%2B"] 32 | , ["&=*" , "%26%3D%2A"] 33 | , ["!'()" , "%21%27%28%29"] 34 | , ["\n" , "%0A"] 35 | , [" " , "%20"] 36 | ]; 37 | 38 | function testEncode() { 39 | for (var i = 0; i < ENCODING.length; ++i) { 40 | var input = ENCODING[i][0]; 41 | var expected = ENCODING[i][1]; 42 | var actual = OAuth.percentEncode(input); 43 | if (expected != actual) { 44 | alert("OAuth.percentEncode(" + input + ") = " + actual); 45 | } 46 | } 47 | } 48 | 49 | function testGetParameters() { 50 | var list = OAuth.getParameterList(null); 51 | if (list == null || !(list instanceof Array) || list.length != 0) { 52 | alert("getParameterList(null) = " + list); 53 | } 54 | list = OAuth.getParameterList(''); 55 | if (list == null || !(list instanceof Array) || list.length != 0) { 56 | alert("getParameterList('') = " + list); 57 | } 58 | var map = OAuth.getParameterMap(null); 59 | if (map == null || (map instanceof Array) || typeof map != "object") { 60 | alert("getParameterMap(null) = " + map); 61 | } 62 | var actual = OAuth.getParameter({x: 'a', y: 'b'}, 'x'); 63 | if (actual != 'a') { 64 | alert("getParameter({}, 'x') = " + actual); 65 | } 66 | actual = OAuth.getParameter([['x', 'a'], ['y', 'b'], ['x', 'c']], 'x'); 67 | if (actual != 'a') { 68 | alert("getParameter([], 'x') = " + actual); 69 | } 70 | var expected = 'OAuth realm="R",oauth_token="T",oauth_w%40%21rd="%23%40%2A%21"'; 71 | actual = OAuth.getAuthorizationHeader('R', [['a', 'b'], ['oauth_token', 'T'], ['oauth_w@!rd', '#@*!']]); 72 | if (actual == null || actual != expected) { 73 | alert("getAuthorizationHeader\n" + expected + " != \n" + actual); 74 | } 75 | actual = OAuth.getAuthorizationHeader('R', {a: 'b', oauth_token: 'T', 'oauth_w@!rd': '#@*!'}); 76 | if (actual == null || actual != expected) { 77 | alert("getAuthorizationHeader\n" + expected + " != \n" + actual); 78 | } 79 | var message = {action: 'http://localhost', parameters: {}}; 80 | OAuth.completeRequest(message, {consumerKey: 'CK', token: 'T'}); 81 | assertMemberEquals(message, 'method', "GET"); 82 | map = message.parameters; 83 | assertMemberEquals(map, 'oauth_consumer_key', 'CK'); 84 | assertMemberEquals(map, 'oauth_token', 'T'); 85 | assertMemberEquals(map, 'oauth_version', '1.0'); 86 | assertMemberNotNull(map, 'oauth_timestamp'); 87 | assertMemberNotNull(map, 'oauth_nonce'); 88 | } 89 | 90 | function assertMemberEquals(map, name, expected) { 91 | var actual = map[name]; 92 | if (actual != expected) { 93 | alert(name + '=' + actual + ' (not ' + expected + ')'); 94 | } 95 | } 96 | 97 | function assertMemberNotNull(map, name) { 98 | var actual = map[name]; 99 | if (!actual) { 100 | alert(name + '=' + actual); 101 | } 102 | } 103 | 104 | var OAUTH_A_BASE_STRING = "GET&http%3A%2F%2Fphotos.example.net%2Fphotos&" 105 | + "file%3Dvacation.jpg%26oauth_consumer_key%3Ddpf43f3p2l4k3l03%26oauth_nonce%3Dkllo9940pd9333jh%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1191242096%26oauth_token%3Dnnch734d00sl2jdk%26oauth_version%3D1.0%26size%3Doriginal"; 106 | 107 | var BASES = // 108 | // label, HTTP method, action, parameters, expected 109 | { "simple" : ["GET", "http://example.com/", {n: "v"}, "GET&http%3A%2F%2Fexample.com%2F&n%3Dv" ] 110 | , "no path" : ["GET", "http://example.com" , {n: "v"}, "GET&http%3A%2F%2Fexample.com%2F&n%3Dv" ] 111 | , "sorting" : ["GET", "http://example.com/", [["n", "AB"], ["n", "{}"]], "GET&http%3A%2F%2Fexample.com%2F&n%3D%257B%257D%26n%3DAB" ] 112 | // , "username in URL": ["GET", "http://U:PW@Example.COM" , null, "GET&http%3A%2F%2FU%3APW%40example.com%2F&" ] 113 | , "capitalized URL": ["GET", "HtTp://Example.CoM/A/b/C" , null, "GET&http%3A%2F%2Fexample.com%2FA%2Fb%2FC&" ] 114 | , "@ in URL" : ["GET", "http://example.com/A@B/C" , null, "GET&http%3A%2F%2Fexample.com%2FA%40B%2FC&" ] 115 | , "punctuated URL" : ["GET", "http://example.com/a;b,c#d", null, "GET&http%3A%2F%2Fexample.com%2Fa%3Bb%2Cc&" ] 116 | , "OAuth A request": ["POST", "https://photos.example.net/request_token", 117 | { oauth_version: "1.0", oauth_consumer_key: "dpf43f3p2l4k3l03" 118 | , oauth_timestamp: "1191242090", oauth_nonce: "hsu94j3884jdopsl" 119 | , oauth_signature_method: "PLAINTEXT", oauth_signature: "ignored" 120 | } 121 | , "POST&https%3A%2F%2Fphotos.example.net%2Frequest_token&" 122 | + "oauth_consumer_key%3Ddpf43f3p2l4k3l03%26oauth_nonce%3Dhsu94j3884jdopsl%26oauth_signature_method%3DPLAINTEXT%26oauth_timestamp%3D1191242090%26oauth_version%3D1.0" ] 123 | , "OAuth A access" : ["GET", "http://photos.example.net/photos", 124 | { file: "vacation.jpg", size: "original" 125 | , oauth_version: "1.0", oauth_consumer_key: "dpf43f3p2l4k3l03", oauth_token: "nnch734d00sl2jdk" 126 | , oauth_timestamp: "1191242096", oauth_nonce: "kllo9940pd9333jh" 127 | , oauth_signature: "ignored", oauth_signature_method: "HMAC-SHA1" 128 | } 129 | , OAUTH_A_BASE_STRING ] 130 | }; 131 | 132 | function testGetBaseString() { 133 | for (var label in BASES) { 134 | try { 135 | var base = BASES[label]; 136 | var b = 0; 137 | var method = base[b++]; 138 | var action = base[b++]; 139 | var parameters = base[b++]; 140 | var expected = base[b++]; 141 | var actual = OAuth.SignatureMethod.getBaseString({method: method, action: action, parameters: parameters}); 142 | if (expected != actual) { 143 | alert(label + "\n" + actual + " (actual)\n" + expected + " (expected)"); 144 | } 145 | } catch(e) { 146 | alert(e); 147 | } 148 | } 149 | // alert("tested OAuth.SignatureMethod.getBaseString"); 150 | } 151 | 152 | var SIGNATURES = 153 | // label, method, consumer secret, token secret, base string, expected 154 | { "HMAC-SHA1.a" : [ "HMAC-SHA1", "cs", null, "bs", "egQqG5AJep5sJ7anhXju1unge2I=" ] 155 | , "HMAC-SHA1.b" : [ "HMAC-SHA1", "cs", "ts", "bs", "VZVjXceV7JgPq/dOTnNmEfO0Fv8=" ] 156 | , "OAuth A access" : [ "HMAC-SHA1", "kd94hf93k423kf44", 157 | "pfkkdhi9sl3r4s00", OAUTH_A_BASE_STRING, 158 | "tR3+Ty81lMeYAr/Fid0kMTYa/WM=" ] 159 | , "PLAINTEXT" : [ "PLAINTEXT", "cs", "ts", "bs", "cs&ts" ] 160 | , "OAuth A request": [ "PLAINTEXT", "kd94hf93k423kf44", null, null, "kd94hf93k423kf44&" ] 161 | }; 162 | 163 | function testGetSignature() { 164 | for (label in SIGNATURES) { 165 | try { 166 | var signature = SIGNATURES[label]; 167 | var s = 0; 168 | var methodName = signature[s++]; 169 | var consumerSecret = signature[s++]; 170 | var tokenSecret = signature[s++]; 171 | var baseString = signature[s++]; 172 | var expected = signature[s++]; 173 | var signer = OAuth.SignatureMethod.newMethod(methodName, 174 | {consumerSecret: consumerSecret, tokenSecret: tokenSecret}); 175 | var actual = signer.getSignature(baseString); 176 | if (expected != actual) { 177 | alert(label + "\n" + actual + " (actual)\n" + expected + " (expected)"); 178 | } 179 | } catch(e) { 180 | alert(label + ": " + e); 181 | } 182 | } 183 | // alert("tested OAuth.SignatureMethod.getSignature"); 184 | } 185 | -------------------------------------------------------------------------------- /oauth.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2008 Netflix, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* Here's some JavaScript software for implementing OAuth. 18 | 19 | This isn't as useful as you might hope. OAuth is based around 20 | allowing tools and websites to talk to each other. However, 21 | JavaScript running in web browsers is hampered by security 22 | restrictions that prevent code running on one website from 23 | accessing data stored or served on another. 24 | 25 | Before you start hacking, make sure you understand the limitations 26 | posed by cross-domain XMLHttpRequest. 27 | 28 | On the bright side, some platforms use JavaScript as their 29 | language, but enable the programmer to access other web sites. 30 | Examples include Google Gadgets, and Microsoft Vista Sidebar. 31 | For those platforms, this library should come in handy. 32 | */ 33 | 34 | // The HMAC-SHA1 signature method calls b64_hmac_sha1, defined by 35 | // http://pajhome.org.uk/crypt/md5/sha1.js 36 | 37 | /* An OAuth message is represented as an object like this: 38 | {method: "GET", action: "http://server.com/path", parameters: ...} 39 | 40 | The parameters may be either a map {name: value, name2: value2} 41 | or an Array of name-value pairs [[name, value], [name2, value2]]. 42 | The latter representation is more powerful: it supports parameters 43 | in a specific sequence, or several parameters with the same name; 44 | for example [["a", 1], ["b", 2], ["a", 3]]. 45 | 46 | Parameter names and values are NOT percent-encoded in an object. 47 | They must be encoded before transmission and decoded after reception. 48 | For example, this message object: 49 | {method: "GET", action: "http://server/path", parameters: {p: "x y"}} 50 | ... can be transmitted as an HTTP request that begins: 51 | GET /path?p=x%20y HTTP/1.0 52 | (This isn't a valid OAuth request, since it lacks a signature etc.) 53 | Note that the object "x y" is transmitted as x%20y. To encode 54 | parameters, you can call OAuth.addToURL, OAuth.formEncode or 55 | OAuth.getAuthorization. 56 | 57 | This message object model harmonizes with the browser object model for 58 | input elements of an form, whose value property isn't percent encoded. 59 | The browser encodes each value before transmitting it. For example, 60 | see consumer.setInputs in example/consumer.js. 61 | */ 62 | 63 | /* This script needs to know what time it is. By default, it uses the local 64 | clock (new Date), which is apt to be inaccurate in browsers. To do 65 | better, you can load this script from a URL whose query string contains 66 | an oauth_timestamp parameter, whose value is a current Unix timestamp. 67 | For example, when generating the enclosing document using PHP: 68 | 69 |