Skip to content

Instantly share code, notes, and snippets.

@nowelium
Created October 17, 2011 13:30
Show Gist options
  • Select an option

  • Save nowelium/1292608 to your computer and use it in GitHub Desktop.

Select an option

Save nowelium/1292608 to your computer and use it in GitHub Desktop.
connect-oauth-google-v2(userinfo request)
const auth = require('connect-auth');
(function (){
// yet another google oauth2
Object.defineProperty(auth, 'GoogleV2', {
get: function() {
return require('./lib/connect-oauth-google-v2/google2');
},
enumerable:true
});
})();
/*!
* Copyright(c) 2010 Ciaran Jessup <ciaranj@gmail.com>
* MIT Licensed
*/
var OAuth= require("oauth").OAuth2,
url = require("url"),
connect = require("connect"),
http = require('http');
var overrideOAuth2 = require('./override_oauth2');
module.exports= function(options, server) {
options= options || {}
var that= {};
var my= {};
// Construct the internal OAuth client
my._oAuth= new OAuth(options.appId, options.appSecret, "", "https://accounts.google.com/o/oauth2/auth", "https://accounts.google.com/o/oauth2/token");
my._redirectUri= options.callback;
my.scope= options.scope || "https://www.googleapis.com/auth/userinfo";
// XXX: Override oauth/lib/_utils.js
overrideOAuth2.override(my._oAuth);
// Give the strategy a name
that.name = options.name || "google2";
// Build the authentication routes required
that.setupRoutes= function(server) {
server.use('/', connect.router(function routes(app){
app.get('/oauth2callback', function(req, res){
req.authenticate([that.name], function(error, authenticated) {
res.writeHead(303, { 'Location': req.session.facebook_redirect_url });
res.end('');
});
});
}));
}
// Declare the method that actually does the authentication
that.authenticate= function(request, response, callback) {
//todo: makw the call timeout ....
var parsedUrl= url.parse(request.url, true);
var self= this;
this._facebook_fail= function(callback) {
request.getAuthDetails()['facebook_login_attempt_failed'] = true;
this.fail(callback);
}
if( request.getAuthDetails()['facebook_login_attempt_failed'] === true ) {
// Because we bounce through authentication calls across multiple requests
// we use this to keep track of the fact we *Really* have failed to authenticate
// so that we don't keep re-trying to authenticate forever.
delete request.getAuthDetails()['facebook_login_attempt_failed'];
self.fail( callback );
}
else {
if( parsedUrl.query && ( parsedUrl.query.code || parsedUrl.query.error === 'access_denied' ) ) {
if( parsedUrl.query.error == 'access_denied' ) {
self._facebook_fail(callback);
} else {
my._oAuth.getOAuthAccessToken(parsedUrl.query.code, {
redirect_uri: my._redirectUri,
grant_type: 'authorization_code'
}, function( error, access_token, refresh_token ){
if( error ) {
return callback(error);
} else {
request.session["access_token"]= access_token;
if( refresh_token ) {
request.session["refresh_token"]= refresh_token;
}
my._oAuth.get(
'https://www.googleapis.com/oauth2/v1/userinfo',
access_token,
function(error, data){
if( error ) {
self._facebook_fail(callback);
} else {
var userInfo = JSON.parse(data);
var profile = {
id: userInfo.id,
email: userInfo.email,
name: userInfo.name,
picture: userInfo.picture
};
self.success(profile, callback);
}
});
}
});
}
}
else {
request.session['facebook_redirect_url']= request.url;
var redirectUrl= my._oAuth.getAuthorizeUrl({redirect_uri : my._redirectUri, scope: my.scope, response_type: 'code' })
self.redirect(response, redirectUrl, callback);
}
}
}
return that;
};
var querystring= require('querystring'),
crypto= require('crypto'),
https= require('https'),
URL= require('url');
//
// XXX: OAuthUtils(node_modules/oauth/lib/_utils.js)
// #isAnEarlyCloseHost is only check *google.com$
// addon *googeapis.com$
//
var isAnEarlyCloseHost = function(hostName){
return hostName.match(".*google.com$") || hostName.match(".*googleapis.com$");
};
module.exports.override = function(oauth){
oauth._request= function(method, url, headers, post_body, access_token, callback) {
var creds = crypto.createCredentials({ });
var parsedUrl= URL.parse( url, true );
if( parsedUrl.protocol == "https:" && !parsedUrl.port ) parsedUrl.port= 443;
var realHeaders= {};
if( headers ) {
for(var key in headers) {
realHeaders[key] = headers[key];
}
}
realHeaders['Host']= parsedUrl.host;
realHeaders['Content-Length']= post_body ? Buffer.byteLength(post_body) : 0;
if( access_token ) {
if( ! parsedUrl.query ) parsedUrl.query= {};
parsedUrl.query[this._accessTokenName]= access_token;
}
var result= "";
var queryStr= querystring.stringify(parsedUrl.query);
if( queryStr ) queryStr= "?" + queryStr;
var options = {
host:parsedUrl.hostname,
port: parsedUrl.port,
path: parsedUrl.pathname + queryStr,
method: method,
headers: realHeaders
};
// Some hosts *cough* google appear to close the connection early / send no content-length header
// allow this behaviour.
var allowEarlyClose = isAnEarlyCloseHost(options.host);
var callbackCalled= false;
function passBackControl( response, result ) {
if(!callbackCalled) {
callbackCalled=true;
if( response.statusCode != 200 ) {
callback({ statusCode: response.statusCode, data: result });
} else {
callback(null, result, response);
}
}
}
request = https.request(options, function (response) {
response.on("data", function (chunk) {
result+= chunk
});
response.on("close", function (err) {
if( allowEarlyClose ) {
passBackControl( response, result );
}
});
response.addListener("end", function () {
passBackControl( response, result );
});
});
request.on('error', function(e) {
callbackCalled= true;
callback(e);
});
if( method == 'POST' && post_body ) {
request.write(post_body);
}
request.end();
};
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment