Created
October 17, 2011 13:30
-
-
Save nowelium/1292608 to your computer and use it in GitHub Desktop.
connect-oauth-google-v2(userinfo request)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 | |
| }); | |
| })(); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /*! | |
| * 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; | |
| }; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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