/* Copyright 2015-2016 PayPal, Inc. */ "use strict"; var configuration = require('../configure'); var client = require('../client'); var utils = require('../utils'); var querystring = require('querystring'); /** * Sets up request body for open id connect module requests * @param {String} path url endpoint * @param {Object} data Payload for HTTP Request * @param {Object|Function} config Configuration parameters such as authorization code or refresh token * @param {Function} cb */ function openIdConnectRequest(path, data, config, cb) { var http_options = { schema: config.openid_connect_schema || configuration.default_options.openid_connect_schema, host: utils.getDefaultApiEndpoint(config.mode) || config.openid_connect_host, port: config.openid_connect_port || configuration.default_options.openid_connect_port, headers: { 'Accept': 'application/json', 'Content-Type': 'application/x-www-form-urlencoded' } }; //Populate Basic Auth header only for endpoints that need it such as tokeninfo if (data.client_id && data.client_secret) { http_options.headers.Authorization = 'Basic ' + new Buffer(data.client_id + ':' + data.client_secret).toString('base64'); } client.invoke('POST', path, querystring.stringify(data), http_options, cb); } /** * @param {Object} config Configurations for settings and Auth * @return {String} client id */ function getClientId(config) { return config.openid_client_id || config.client_id || configuration.default_options.openid_client_id || configuration.default_options.client_id; } /** * @param {Object} config Configurations for settings and Auth * @return {String} client secret */ function getClientSecret(config) { return config.openid_client_secret || config.client_secret || configuration.default_options.openid_client_secret || configuration.default_options.client_secret; } /** * Configurations for settings and Auth * @return {String} redirect uri */ function getRedirectUri(config) { return config.openid_redirect_uri || configuration.default_options.openid_redirect_uri; } /** * Obtain a user’s consent to make Identity API calls on their behalf by redirecting them * to authorization endpoint * @param {Data} data Payload associated with API request * @param {Object} config Configurations for settings and Auth * @return {String} authorize url */ function authorizeUrl(data, config) { config = config || configuration.default_options; data = data || {}; //Use mode provided, live or sandbox to construct authorize_url, sandbox is default var url = 'https://www.' + utils.getDefaultEndpoint(config.mode) + '/signin/authorize' || config.authorize_url; data = utils.merge({ 'client_id': getClientId(config), 'scope': 'openid', 'response_type': 'code', 'redirect_uri': getRedirectUri(config) }, data); return url + '?' + querystring.stringify(data); } /** * Direct user to logout url to end session * @param {Data} data Payload associated with API request * @param {Object} config Configurations for settings and Auth * @return {String} logout url */ function logoutUrl(data, config) { config = config || configuration.default_options; data = data || {}; var url = 'https://www.' + utils.getDefaultEndpoint(config.mode) + '/webapps/auth/protocol/openidconnect/v1/endsession' || config.logout_url; if (typeof data === 'string') { data = { 'id_token': data }; } data = utils.merge({ 'logout': 'true', 'redirect_uri': getRedirectUri(config) }, data); return url + '?' + querystring.stringify(data); } /** * Grant a new access token, using a refresh token * @param {Object} data Payload associated with API request * @param {Object|Function} config Configurations for settings and Auth * @param {Function} cb Callback function */ function tokenInfoRequest(data, config, cb) { if (typeof config === 'function') { cb = config; config = configuration.default_options; } else if (!config) { config = configuration.default_options; } data = utils.merge({ 'client_id': getClientId(config), 'client_secret': getClientSecret(config) }, data); openIdConnectRequest('/v1/identity/openidconnect/tokenservice', data, config, cb); } /** * Retrieve user profile attributes * @param {Object} data Payload associated with API request * @param {Object|Function} config Configurations for settings and Auth * @param {Function} cb Callback function */ function userInfoRequest(data, config, cb) { if (typeof config === 'function') { cb = config; config = configuration.default_options; } else if (!config) { config = configuration.default_options; } if (typeof data === 'string') { data = { 'access_token': data }; } data = utils.merge({ 'schema': 'openid' }, data); openIdConnectRequest('/v1/identity/openidconnect/userinfo', data, config, cb); } /** * Use log in with PayPal to avoid storing user data on the system * @return {Object} openidconnect functions */ function openIdConnect() { return { tokeninfo: { create: function (data, config, cb) { if (typeof data === 'string') { data = { 'code': data }; } data.grant_type = 'authorization_code'; tokenInfoRequest(data, config, cb); }, refresh: function (data, config, cb) { if (typeof data === 'string') { data = { 'refresh_token': data }; } data.grant_type = 'refresh_token'; tokenInfoRequest(data, config, cb); } }, authorizeUrl: authorizeUrl, logoutUrl: logoutUrl, userinfo: { get: userInfoRequest }, //entries below are deprecated but provided for compatibility with 0.* versions authorize_url: authorizeUrl, logout_url: logoutUrl }; } module.exports = openIdConnect;