dwyl/hapi-auth-github

View on GitHub
lib/index.js

Summary

Maintainability
A
1 hr
Test Coverage
'use strict';

var OPTIONS;      // global object set when plugin loads
var crypto = require('crypto');      // http://nodejs.org/api/crypto.html
var pkg = require('../package.json');
var request = require('./http_request');
var querystring = require('querystring'); // nodejs.org/api/querystring.html

/**
 * make_post_data simply extracts the code and state (hash) from the request
 * and combines those data with the GitHub Client Id & Secret as a query string
 * @param {Object} req - the request object sent by GitHub with code & state
 * @returns {Object} the stringified object required to request OAuth2 Token
 */
function make_post_data (req) {
  return querystring.stringify({
    client_id: process.env.GITHUB_CLIENT_ID,
    client_secret: process.env.GITHUB_CLIENT_SECRET,
    code: req.query.code,
    state: req.query.state
  });
}

/**
 * http.request options for requesting the OAuth2 token
 * see: developer.github.com/v3/oauth/#github-redirects-back-to-your-site
 * @param {String} post_data the POST data we are sending to GitHub
 * @returns {Object} data & headers we are sending to GitHub in our HTTP request
 */
function token_options (post_data) {
  return {
    body: post_data, // see make_post_data above
    headers: {
      'Accept': 'application/json',
      'Content-Type': 'application/x-www-form-urlencoded',
      'Content-Length': post_data.length
    },
    hostname: process.env.GITHUB_HOSTNAME || 'github.com',
    method: 'POST',
    path: '/login/oauth/access_token',
    port: 443
  };
}
/**
 * http request to get the profile of the person that just authenticated
 * see: https://developer.github.com/v3/users/#get-the-authenticated-user
 * @param {Object} access_json returned by GitHub OAuth access_token request.
 * @returns {Object} data & headers we are sending to GitHub in our HTTP request
 */
function user_options (access_json) {
  return {
    headers: {
      'Authorization': 'token ' + access_json.access_token,
      'Accept': 'application/json',
      'User-Agent': 'hapi-auth-github' // a User-Agent is *REQUIRED*!!
    },
    hostname: process.env.GITHUB_API_HOSTNAME || 'api.github.com',
    method: 'GET',
    path: '/user',
    port: 443
  };
}

/**
 * this plugin creates the github Oauth Callback URL
 * e.g: /githubauth where github calls back to with the OAuth code
 * @param {Object} server - the Hapi server object/instance
 * @param {Object} options - any valid request options (e.g. method or path)
 * @param {Function} next - called once plugin has been registered
 * @returns {Boolean} callback - no point returning anything else ...!
 */
exports.register = function (server, options, next) {
  OPTIONS = options; // should we check the options have been set?
  server.route([
    {
      method: 'GET', // ping
      path: process.env.GITHUB_AUTH_REDIRECT_URL, // must be identical to Authorized callback URL
      config: { auth: false },
      handler: function (req, reply) {
        var post_data = make_post_data(req);
        var options1 = token_options(post_data);

        request(options1, function (err, oauth_access_token_json) {
          var options2;
          var profile = null;

          server.log('error', err); // see: github.com/dwyl/hapi-error#logging
          options2 = user_options(oauth_access_token_json);

          request(options2, function (oauth_err, user_profile) {
            if (oauth_err) {
              server.log('error', oauth_err); // add "good" logging to see logs
            } else {
              profile = user_profile;
            }
            OPTIONS.handler(req, reply, oauth_access_token_json, profile);

            return true;
          });
        });
      }
    }
  ]);

  return next(); // everything worked, continue booting the hapi server!
};

exports.register.attributes = { pkg: pkg };

module.exports.login_url = function () {
  var params = {
    client_id: process.env.GITHUB_CLIENT_ID,
    redirect_uri: process.env.BASE_URL + process.env.GITHUB_AUTH_REDIRECT_URL,
    scope: OPTIONS.SCOPE,
    state: crypto.createHash('sha256')
      .update(Math.random().toString())
      .digest('hex')
  };
  var qs = querystring.stringify(params);
  var url = 'https://github.com/login/oauth/authorize?' + qs;

  return url;
};