Home Reference Source Test Repository

src/oauth2_connector.js

'use strict';
import Bluebird from 'bluebird';
import config from 'config';
import {
  OAuth2
}
from '@hoist/oauth';

/**
 * @protected
 * The base OAuth2 Connector class used for Hoist Connectors to implement OAuth2 flows
 * @implements {ConnectorInterface}
 */
export default class OAuth2ConnectorBase {

  /**
   * @protected
   * create a new OAuth2Connector
   * @param {object} configuration - the configuration details for this connector
   * @param {string} configuration.clientId - the OAuth2 client id
   * @param {string} configuration.clientSecret - the OAuth2 client secret
   * @param {string} configuration.baseSite - the base uri to use for authorization calls
   * @param {string} [configuration.authorizationPath=/oauth/authorize] - the path to send users to authorise access
   * @param {string} [configuration.accessTokenPath=/oauth/access_token] - the path to use to retrieve access tokens
   * @param {object} [configuration.customHeaders] - any custom headers to send
   */
  constructor(configuration) {
    this._auth = Bluebird.promisifyAll(new OAuth2(configuration.clientId, configuration.clientSecret, configuration.baseSite, configuration.authorizationPath, configuration.accessTokenPath, configuration.customHeaders));
  }

  /**
   * Populate any extra params needed to grant access
   * @protected
   * @param {AuthorizationStore} authorization - the users authorisation store
   * @returns {Promise<object>} - an object containing key value pairs to send with the client to the authorization url
   */
  _authorizeParams(authorization) {
    return Promise.resolve({
      redirect_uri: `https://${config.get('Hoist.domains.bouncer')}/bounce`
    });
  }

  /**
   * Populate any extra params needed to request the access token
   * @protected
   * @param {AuthorizationStore} authorization - the users authorisation store
   * @returns {Promise<object>} - an object containing key value pairs to send with the access token request
   */
  _accessParams(authorization) {
    return Promise.resolve();
  }
  _processResults(results) {
    return Promise.resolve();
  }

  /**
   * perform an authorized request
   * @param {string} method - the HTTP method to call
   * @param {string} requestUri - the uri of the request to call
   * @param {object} body - the data to send
   * @param {string} contentType - the contentType header
   */
  _performRequest(method, requestUri, body, contentType) {
    let headers = {
      'Content-Type': contentType,
      'User-Agent': 'Hoist',
      'Authorization': this._auth.buildAuthHeader(this._accessToken)
    };
    return this._auth._requestAsync(method, requestUri, headers, this._accessToken);
  }

  /**
   * authorize the oauth connection with existing parameters
   * @param {<AuthorizationStore>} authorization - the users authorization
   */
  authorize(authorization) {
    this._accessToken = authorization.get('AccessToken');
    this._refreshToken = authorization.get('RefreshToken');
  }

  /**
   * @param {AuthorizationStore} authorization - the users authorization
   */
  receiveBounce(authorization) {
    var authStep = authorization.get('currentStep');
    if (!authStep) {
      //no authorization has been done yet so lets get the authorization url and redirec the user there
      return this._authorizeParams(authorization)
        .then((params) => {
          return this._auth.getAuthorizeUrl(params);
        }).then((authUri) => {
          //set the step so we know to get the access token when they return
          return authorization.set('currentStep', 'authorization')
            .then(() => {
              //redirect the user
              return authorization.redirect(authUri);
            })
        });
    } else if (authStep === 'authorization') {
      return this._accessParams(authorization)
        .then((params) => {
          return this._auth.getOAuthAccessTokenAsync(authorization.query.code, params);
        }).then((results) => {
          return authorization.set('AccessToken', results[0])
            .then(() => {
              return authorization.set('RefreshToken', results[1]);
            }).then(() => {
              return this._processResults(results[2]);
            }).then(() => {
              return authorization.done();
            });
        });
    }
    //default just mark as done
    return authorization.done();
  }

}