OAuth2 getOAuthAccessToken now POSTs rather than GET as per the spec (v20)

This commit is contained in:
ciaranj
2011-08-15 23:30:47 +01:00
parent 0643395b2e
commit 707b8f77b2
5 changed files with 34 additions and 22 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
node_modules

View File

@ -10,6 +10,7 @@ Also provides rudimentary OAuth2 support, tested against facebook connect and gi
Change History Change History
============== ==============
* 0.9.4 - Support for OAuth providers that drop connections (don't send response lengths? [Google]) And change OAuth2 getOAuthAccessToken to POST rather than GET ( Possible Breaking change!!! ... re-tested against Google, Github, Facebook, FourSquare and Janrain and seems ok .. is closer to the spec (v20) )
* 0.9.3 - Adds support for following 301 redirects (Thanks bdickason) * 0.9.3 - Adds support for following 301 redirects (Thanks bdickason)
* 0.9.2 - Correct content length calculated for non-ascii post bodies (Thanks selead) * 0.9.2 - Correct content length calculated for non-ascii post bodies (Thanks selead)
Allowed for configuration of the 'access token' name used when requesting protected resources (OAuth2) Allowed for configuration of the 'access token' name used when requesting protected resources (OAuth2)
@ -20,7 +21,7 @@ Allowed for configuration of the 'access token' name used when requesting protec
* 0.8.2 - The request returning methods will now write the POST body if provided (Chris Anderson), the code responsible for manipulating the headers is a bit safe now when working with other code (Paul McKellar) and tweaked the package.json to use index.js instead of main.js * 0.8.2 - The request returning methods will now write the POST body if provided (Chris Anderson), the code responsible for manipulating the headers is a bit safe now when working with other code (Paul McKellar) and tweaked the package.json to use index.js instead of main.js
* 0.8.1 - Added mechanism to get hold of a signed Node Request object, ready for attaching response listeners etc. (Perfect for streaming APIs) * 0.8.1 - Added mechanism to get hold of a signed Node Request object, ready for attaching response listeners etc. (Perfect for streaming APIs)
* 0.8.0 - Standardised method capitalisation, the old getOauthAccessToken is now getOAuthAccessToken (Breaking change to existing code) * 0.8.0 - Standardised method capitalisation, the old getOauthAccessToken is now getOAuthAccessToken (Breaking change to existing code)
* 0.7.7 - Looks like non oauth_ parameters where appearing within the Authorization headers, which I believe to be inccorrect. * 0.7.7 - Looks like non oauth_ parameters where appearing within the Authorization headers, which I believe to be incorrect.
* 0.7.6 - Added in oauth_verifier property to getAccessToken required for 1.0A * 0.7.6 - Added in oauth_verifier property to getAccessToken required for 1.0A
* 0.7.5 - Added in a main.js to simplify the require'ing of OAuth * 0.7.5 - Added in a main.js to simplify the require'ing of OAuth
* 0.7.4 - Minor change to add an error listener to the OAuth client (thanks troyk) * 0.7.4 - Minor change to add an error listener to the OAuth client (thanks troyk)

View File

@ -22,16 +22,11 @@ exports.OAuth2.prototype.setAccessTokenName= function ( name ) {
this._accessTokenName= name; this._accessTokenName= name;
} }
exports.OAuth2.prototype._getAccessTokenUrl= function( params ) { exports.OAuth2.prototype._getAccessTokenUrl= function() {
var params= params || {}; return this._baseSite + this._accessTokenUrl; /* + "?" + querystring.stringify(params); */
params['client_id'] = this._clientId;
params['client_secret'] = this._clientSecret;
params['type']= 'web_server';
return this._baseSite + this._accessTokenUrl + "?" + querystring.stringify(params);
} }
exports.OAuth2.prototype._request= function(method, url, headers, access_token, callback) { exports.OAuth2.prototype._request= function(method, url, headers, post_body, access_token, callback) {
var creds = crypto.createCredentials({ }); var creds = crypto.createCredentials({ });
var parsedUrl= URL.parse( url, true ); var parsedUrl= URL.parse( url, true );
@ -45,19 +40,19 @@ exports.OAuth2.prototype._request= function(method, url, headers, access_token,
} }
realHeaders['Host']= parsedUrl.host; realHeaders['Host']= parsedUrl.host;
//TODO: Content length should be dynamic when dealing with POST methods.... realHeaders['Content-Length']= post_body ? Buffer.byteLength(post_body) : 0;
realHeaders['Content-Length']= 0;
if( access_token ) { if( access_token ) {
if( ! parsedUrl.query ) parsedUrl.query= {}; if( ! parsedUrl.query ) parsedUrl.query= {};
parsedUrl.query[this._accessTokenName]= access_token; parsedUrl.query[this._accessTokenName]= access_token;
} }
var result= ""; var result= "";
var queryStr= querystring.stringify(parsedUrl.query);
if( queryStr ) queryStr= "?" + queryStr;
var options = { var options = {
host:parsedUrl.hostname, host:parsedUrl.hostname,
port: parsedUrl.port, port: parsedUrl.port,
path: parsedUrl.pathname + "?" + querystring.stringify(parsedUrl.query), path: parsedUrl.pathname + queryStr,
method: method, method: method,
headers: realHeaders headers: realHeaders
}; };
@ -90,12 +85,14 @@ exports.OAuth2.prototype._request= function(method, url, headers, access_token,
passBackControl( response, result ); passBackControl( response, result );
}); });
}); });
request.on('error', function(e) { request.on('error', function(e) {
callbackCalled= true; callbackCalled= true;
callback(e); callback(e);
}); });
if( method == 'POST' && post_body ) {
request.write(post_body);
}
request.end(); request.end();
} }
@ -109,9 +106,19 @@ exports.OAuth2.prototype.getAuthorizeUrl= function( params ) {
exports.OAuth2.prototype.getOAuthAccessToken= function(code, params, callback) { exports.OAuth2.prototype.getOAuthAccessToken= function(code, params, callback) {
var params= params || {}; var params= params || {};
params['client_id'] = this._clientId;
params['client_secret'] = this._clientSecret;
params['type']= 'web_server';
params['code']= code; params['code']= code;
this._request("POST", this._getAccessTokenUrl(params), {}, null, function(error, data, response) { var post_data= querystring.stringify( params );
var post_headers= {
'Content-Type': 'application/x-www-form-urlencoded'
};
this._request("POST", this._getAccessTokenUrl(), post_headers, post_data, null, function(error, data, response) {
console.log( 'e> ' + error)
if( error ) callback(error); if( error ) callback(error);
else { else {
var results; var results;
@ -137,9 +144,9 @@ exports.OAuth2.prototype.getOAuthAccessToken= function(code, params, callback) {
// Deprecated // Deprecated
exports.OAuth2.prototype.getProtectedResource= function(url, access_token, callback) { exports.OAuth2.prototype.getProtectedResource= function(url, access_token, callback) {
this._request("GET", url, {}, access_token, callback ); this._request("GET", url, {}, "", access_token, callback );
} }
exports.OAuth2.prototype.get= function(url, access_token, callback) { exports.OAuth2.prototype.get= function(url, access_token, callback) {
this._request("GET", url, {}, access_token, callback ); this._request("GET", url, {}, "", access_token, callback );
} }

View File

@ -1,8 +1,11 @@
{ "name" : "oauth" { "name" : "oauth"
, "description" : "Library for interacting with OAuth 1.0, 1.0A, 2 and Echo. Provides simplified client access and allows for construction of more complex apis and OAuth providers." , "description" : "Library for interacting with OAuth 1.0, 1.0A, 2 and Echo. Provides simplified client access and allows for construction of more complex apis and OAuth providers."
, "version" : "0.9.3" , "version" : "0.9.4"
, "directories" : { "lib" : "./lib" } , "directories" : { "lib" : "./lib" }
, "main" : "index.js" , "main" : "index.js"
, "author" : "Ciaran Jessup <ciaranj@gmail.com>" , "author" : "Ciaran Jessup <ciaranj@gmail.com>"
, "repository" : { "type":"git", "url":"http://github.com/ciaranj/node-oauth.git" } , "repository" : { "type":"git", "url":"http://github.com/ciaranj/node-oauth.git" }
, "devDependencies": {
"vows": "0.5.x"
}
} }

View File

@ -6,7 +6,7 @@ vows.describe('OAuth2').addBatch({
'When handling the access token response': { 'When handling the access token response': {
topic: new OAuth2(), topic: new OAuth2(),
'we should correctly extract the token if received as form-data': function (oa) { 'we should correctly extract the token if received as form-data': function (oa) {
oa._request= function( method, url, fo, bar, callback) { oa._request= function( method, url, fo, bar, bleh, callback) {
callback(null, "access_token=access&refresh_token=refresh"); callback(null, "access_token=access&refresh_token=refresh");
}; };
oa.getOAuthAccessToken("", {}, function(error, access_token, refresh_token) { oa.getOAuthAccessToken("", {}, function(error, access_token, refresh_token) {
@ -15,7 +15,7 @@ vows.describe('OAuth2').addBatch({
}); });
}, },
'we should correctly extract the token if received as a JSON literal': function (oa) { 'we should correctly extract the token if received as a JSON literal': function (oa) {
oa._request= function( method, url, fo, bar, callback) { oa._request= function(method, url, headers, post_body, access_token, callback) {
callback(null, '{"access_token":"access","refresh_token":"refresh"}'); callback(null, '{"access_token":"access","refresh_token":"refresh"}');
}; };
oa.getOAuthAccessToken("", {}, function(error, access_token, refresh_token) { oa.getOAuthAccessToken("", {}, function(error, access_token, refresh_token) {