Repository: auth0/node-auth0
Pull request #592 (2021-03-11 13:19:27)

feat(orgs): Support Organization feature
### Changes

Adding organizations endpoints.

### Testing

Please describe how this can be tested by reviewers. Be specific about anything not tested and reasons why. If this library has unit and/or integration testing, tests should be added for new functionality and existing tests should complete without errors. 

- [x] This change adds unit test coverage
- [ ] This change adds integration test coverage

### Checklist

- [ ] I have read the [Auth0 general contribution guidelines](https://github.com/auth0/open-source-template/blob/master/GENERAL-CONTRIBUTING.md)
- [ ] I have read the [Auth0 Code of Conduct](https://github.com/auth0/open-source-template/blob/master/CODE-OF-CONDUCT.md)
- [ ] All existing and new tests complete without errors


yacineMTB: All the comments from @ubenzer (+ a few more) should be addressed in https://github.com/auth0/node-auth0/pull/592/commits/f059d95304c573d2a76173793e27a86a9cef75f3. It would be nice if someone looked this commit over too
cocojoe: @yacineMTB now that it's been confirmed as ready to move to review, it will move into SDKs review cycle now. @adamjmcgrath and @davidpatrick will walk through and review.
mcastany: @adamjmcgrath I noticed some jsdoc needed updating so I pushed https://github.com/auth0/node-auth0/pull/592/commits/33f81121704508a911aabe2bd62fee4248cbdea7 to update them
mcastany: @madsharm  Applied here - https://github.com/auth0/node-auth0/pull/592/commits/29731bb7b8febeecdfff9a98f90aacf8ce216bb5 - can you review again ?
mcastany: that was fast

Patch:
diff --git a/src/management/JobsManager.js b/src/management/JobsManager.js
index 8ac10de46..cca9c74c5 100644
--- a/src/management/JobsManager.js
+++ b/src/management/JobsManager.js
@@ -364,6 +364,7 @@ JobsManager.prototype.errors = function(params, cb) {
  *
  * @param   {Object}    data          User data object.
  * @param   {String}    data.user_id  ID of the user to be verified.
+ * @param   {String}    [data.organization_id] Organization ID
  * @param   {String}    [data.client_id] client_id of the client (application). If no value provided, the global Client ID will be used.
  * @param   {Object}    [data.identity] Used to verify secondary, federated, and passwordless-email identities.
  * @param   {String}    data.identity.user_id user_id of the identity.
diff --git a/src/management/OrganizationsManager.js b/src/management/OrganizationsManager.js
new file mode 100644
index 000000000..1e2dc26d0
--- /dev/null
+++ b/src/management/OrganizationsManager.js
@@ -0,0 +1,843 @@
+var ArgumentError = require('rest-facade').ArgumentError;
+var utils = require('../utils');
+var Auth0RestClient = require('../Auth0RestClient');
+var RetryRestClient = require('../RetryRestClient');
+
+/**
+ * Simple facade for consuming a REST API endpoint.
+ * @external RestClient
+ * @see https://github.com/ngonzalvez/rest-facade
+ */
+
+/**
+ * @class OrganizationsManager
+ * The organizations class provides a simple abstraction for performing CRUD operations
+ * on Auth0 OrganizationsManager.
+ * @constructor
+ * @memberOf module:management
+ *
+ * @param {Object} options            The client options.
+ * @param {String} options.baseUrl    The URL of the API.
+ * @param {Object} [options.headers]  Headers to be included in all requests.
+ * @param {Object} [options.retry]    Retry Policy Config
+ */
+var OrganizationsManager = function(options) {
+  if (options === null || typeof options !== 'object') {
+    throw new ArgumentError('Must provide manager options');
+  }
+
+  if (options.baseUrl === null || options.baseUrl === undefined) {
+    throw new ArgumentError('Must provide a base URL for the API');
+  }
+
+  if ('string' !== typeof options.baseUrl || options.baseUrl.length === 0) {
+    throw new ArgumentError('The provided base URL is invalid');
+  }
+
+  /**
+   * Options object for the Rest Client instance.
+   *
+   * @type {Object}
+   */
+  var clientOptions = {
+    headers: options.headers,
+    query: { repeatParams: false }
+  };
+
+  /**
+   * Provides an abstraction layer for performing CRUD operations on
+   * {@link https://auth0.com/docs/api/v2}.
+   *
+   * @type {external:RestClient}
+   */
+  var auth0RestClient = new Auth0RestClient(
+    options.baseUrl + '/organizations/:id',
+    clientOptions,
+    options.tokenProvider
+  );
+  this.organizations = new RetryRestClient(auth0RestClient, options.retry);
+
+  var connectionsInRoleClient = new Auth0RestClient(
+    options.baseUrl + '/organizations/:id/enabled_connections/:connection_id',
+    clientOptions,
+    options.tokenProvider
+  );
+  this.connections = new RetryRestClient(connectionsInRoleClient, options.retry);
+
+  var membersClient = new Auth0RestClient(
+    options.baseUrl + '/organizations/:id/members/:user_id',
+    clientOptions,
+    options.tokenProvider
+  );
+  this.members = new RetryRestClient(membersClient, options.retry);
+
+  var invitationClient = new Auth0RestClient(
+    options.baseUrl + '/organizations/:id/invitations/:invitation_id',
+    clientOptions,
+    options.tokenProvider
+  );
+  this.invitations = new RetryRestClient(invitationClient, options.retry);
+
+  var rolesClient = new Auth0RestClient(
+    options.baseUrl + '/organizations/:id/members/:user_id/roles',
+    clientOptions,
+    options.tokenProvider
+  );
+  this.roles = new RetryRestClient(rolesClient, options.retry);
+
+  var organizationByNameClient = new Auth0RestClient(
+    options.baseUrl + '/organizations/name/:name',
+    clientOptions,
+    options.tokenProvider
+  );
+  this.organizationsByName = new RetryRestClient(organizationByNameClient, options.retry);
+};
+
+/**
+ * Create a new organization.
+ *
+ * @method    create
+ * @memberOf  module:management.OrganizationsManager.prototype
+ *
+ * @example
+ * management.organizations.create(data, function (err) {
+ *   if (err) {
+ *     // Handle error.
+ *   }
+ *
+ *   // Organization created.
+ * });
+ *
+ * @param   {Object}    data     Organization data object.
+ * @param   {Function}  [cb]     Callback function.
+ *
+ * @return  {Promise|undefined}
+ */
+utils.wrapPropertyMethod(OrganizationsManager, 'create', 'organizations.create');
+
+/**
+ * Get all organizations.
+ *
+ * @method    getAll
+ * @memberOf  module:management.OrganizationsManager.prototype
+ *
+ * @example <caption>
+ *   This method takes an optional object as first argument that may be used to
+ *   specify pagination settings. If pagination options are not present,
+ *   the first page of a limited number of results will be returned.
+ * </caption>
+ *
+ * // Pagination settings.
+ * var params = {
+ *   per_page: 10,
+ *   page: 0
+ * };
+ *
+ * management.organizations.getAll(params, function (err, organizations) {
+ *   console.log(organizations.length);
+ * });
+ *
+ * @param   {Object}    [params]          Organizations parameters.
+ * @param   {Number}    [params.per_page] Number of results per page.
+ * @param   {Number}    [params.page]     Page number, zero indexed.
+ * @param   {Function}  [cb]              Callback function.
+ *
+ * @return  {Promise|undefined}
+ */
+utils.wrapPropertyMethod(OrganizationsManager, 'getAll', 'organizations.getAll');
+
+/**
+ * Get an Auth0 organization.
+ *
+ * @method    getByID
+ * @memberOf  module:management.OrganizationsManager.prototype
+ *
+ * @example
+ * management.organizations.getByID({ id: ORGANIZATION_ID }, function (err, role) {
+ *   if (err) {
+ *     // Handle error.
+ *   }
+ *
+ *   console.log(organization);
+ * });
+ *
+ * @param   {Object}    params        Organization parameters.
+ * @param   {String}    params.id     Organization ID.
+ * @param   {Function}  [cb]          Callback function.
+ *
+ * @return  {Promise|undefined}
+ */
+utils.wrapPropertyMethod(OrganizationsManager, 'getByID', 'organizations.get');
+
+/**
+ * Get an Auth0 organization.
+ *
+ * @method    getByName
+ * @memberOf  module:management.OrganizationsManager.prototype
+ *
+ * @example
+ * management.organizations.getByName({ name: ORGANIZATION_NAME}, function (err, role) {
+ *   if (err) {
+ *     // Handle error.
+ *   }
+ *
+ *   console.log(organization);
+ * });
+ *
+ * @param   {Object}    params        Organization parameters.
+ * @param   {String}    params.name   Organization name.
+ * @param   {Function}  [cb]          Callback function.
+ *
+ * @return  {Promise|undefined}
+ */
+utils.wrapPropertyMethod(OrganizationsManager, 'getByName', 'organizationsByName.get');
+
+/**
+ * Update an existing organization.
+ *
+ * @method    update
+ * @memberOf  module:management.OrganizationsManager.prototype
+ *
+ * @example
+ * var data = { display_name: 'New name' };
+ * var params = { id: ORGANIZATION_ID };
+ *
+ * management.organizations.update(params, data, function (err, organization) {
+ *   if (err) {
+ *     // Handle error.
+ *   }
+ *
+ *   console.log(organization.name);  // 'New name'
+ * });
+ *
+ * @param   {Object}    params        Organization parameters.
+ * @param   {String}    params.id     Organization ID.
+ * @param   {Object}    data          Updated organization data.
+ * @param   {Function}  [cb]          Callback function.
+ *
+ * @return  {Promise|undefined}
+ */
+utils.wrapPropertyMethod(OrganizationsManager, 'update', 'organizations.patch');
+
+/**
+ * Delete an existing organization.
+ *
+ * @method    delete
+ * @memberOf  module:management.OrganizationsManager.prototype
+ *
+ * @example
+ * management.organizations.delete({ id: ORGANIZATION_ID }, function (err) {
+ *   if (err) {
+ *     // Handle error.
+ *   }
+ *
+ *   // Organization deleted.
+ * });
+ *
+ * @param   {Object}    params        Organization parameters.
+ * @param   {String}    params.id     Organization ID.
+ * @param   {Function}  [cb]          Callback function.
+ *
+ * @return  {Promise|undefined}
+ */
+utils.wrapPropertyMethod(OrganizationsManager, 'delete', 'organizations.delete');
+
+/**
+ **** Organization Connections
+ */
+
+/**
+ * Get Enabled Connections in a Organization
+ *
+ * @method    getEnabledConnections
+ * @memberOf  module:management.OrganizationsManager.prototype
+ *
+ * @example
+ * var params = {id : 'ORGANIZATION_ID'}
+ * @example <caption>
+ *   This method takes an organization ID and returns the enabled connections in an Organization
+ * </caption>
+ *
+ * management.organizations.getEnabledConnections( {id : 'ORGANIZATION_ID'}, function (err, enabled_connections) {
+ *   console.log(enabled_connections);
+ * });
+ *
+ * @param   {String}    [organization_id]   Organization ID
+ * @param   {Function}  [cb]                Callback function.
+ *
+ * @return  {Promise|undefined}
+ */
+OrganizationsManager.prototype.getEnabledConnections = function(params, callback) {
+  return this.connections.getAll(params, callback);
+};
+
+/**
+ * Get Enabled Connection in a Organization
+ *
+ * @method    getEnabledConnection
+ * @memberOf  module:management.OrganizationsManager.prototype
+ *
+ * @example
+ * var params = {id : 'ORGANIZATION_ID', connection_id: 'CONNECTION_ID'}
+ * @example <caption>
+ *   This methods takes the organization ID and connection ID and returns the enabled connection
+ * </caption>
+ *
+ * management.organizations.getEnabledConnections( {id : 'ORGANIZATION_ID', connection_id: 'CONNECTION_ID'}, function (err, enabled_connection) {
+ *   console.log(enabled_connection);
+ * });
+ *
+ * @param   {String}    [organization_id]   Organization ID
+ * @param   {Function}  [cb]                Callback function.
+ *
+ * @return  {Promise|undefined}
+ */
+OrganizationsManager.prototype.getEnabledConnection = function(params, callback) {
+  return this.connections.get(params, callback);
+};
+
+/**
+ * Add an enabled connection for an organization
+ *
+ * @method    addEnabledConnection
+ * @memberOf  module:management.OrganizationsManager.prototype
+ *
+ * @example
+ * var params =  { id :'ORGANIZATION_ID'};
+ * var data = { "connection_id" : "CONNECTION_ID", assign_membership_on_login: false };
+ *
+ * management.organizations.addEnabledConnection(params, data, function (err) {
+ *   if (err) {
+ *     // Handle error.
+ *   }
+ * });
+ *
+ * @param   {String}    params.id             ID of the Organization.
+ * @param   {Object}    data                  enable connection data
+ * @param   {String}    data.connection_id    connection ID to enable
+ * @param   {Boolean}   data.assign_membership_on_login flag to allow assign membership on login
+ * @param   {Function}  [cb]                  Callback function.
+ *
+ * @return  {Promise|undefined}
+ */
+
+OrganizationsManager.prototype.addEnabledConnection = function(params, data, cb) {
+  data = data || {};
+  params = params || {};
+
+  if (!params.id) {
+    throw new ArgumentError('The organization ID passed in params cannot be null or undefined');
+  }
+  if (typeof params.id !== 'string') {
+    throw new ArgumentError('The organization ID has to be a string');
+  }
+
+  if (cb && cb instanceof Function) {
+    return this.connections.create(params, data, cb);
+  }
+
+  return this.connections.create(params, data);
+};
+
+/**
+ * Remove an enabled connection from an organization
+ *
+ * @method    removeEnabledConnection
+ * @memberOf  module:management.OrganizationsManager.prototype
+ *
+ * @example
+ * var params =  { id :'ORGANIZATION_ID', connection_id: 'CONNECTION_ID' };
+ *
+ * management.organizations.removeEnabledConnection(params, function (err) {
+ *   if (err) {
+ *     // Handle error.
+ *   }
+ * });
+ *
+ * @param   {String}    params.id             ID of the Organization.
+ * @param   {String}    params.connection_id  ID of the Connection.
+ * @param   {Function}  [cb]                  Callback function.
+ *
+ * @return  {Promise|undefined}
+ */
+
+OrganizationsManager.prototype.removeEnabledConnection = function(params, cb) {
+  params = params || {};
+
+  if (!params.id) {
+    throw new ArgumentError('The organization ID passed in params cannot be null or undefined');
+  }
+  if (typeof params.id !== 'string') {
+    throw new ArgumentError('The organization ID has to be a string');
+  }
+
+  if (!params.connection_id) {
+    throw new ArgumentError('The connection ID passed in params cannot be null or undefined');
+  }
+  if (typeof params.connection_id !== 'string') {
+    throw new ArgumentError('The connection ID has to be a string');
+  }
+
+  if (cb && cb instanceof Function) {
+    return this.connections.delete(params, {}, cb);
+  }
+
+  return this.connections.delete(params, {});
+};
+
+/**
+ * Update an enabled connection from an organization
+ *
+ * @method    updateEnabledConnection
+ * @memberOf  module:management.OrganizationsManager.prototype
+ *
+ * @example
+ * var params =  { id :'ORGANIZATION_ID', connection_id: 'CONNECTION_ID' };
+ * var data = { assign_membership_on_login: true };
+ *
+ * management.organizations.updateEnabledConnection(params, data, function (err) {
+ *   if (err) {
+ *     // Handle error.
+ *   }
+ * });
+ *
+ * @param   {String}    params.id             ID of the Organization.
+ * @param   {String}    params.connection_id  ID of the Connection.
+ * @param   {Object}    data                  Updated connection.
+ * @param   {Function}  [cb]                  Callback function.
+ *
+ * @return  {Promise|undefined}
+ */
+
+OrganizationsManager.prototype.updateEnabledConnection = function(params, data, cb) {
+  data = data || {};
+  params = params || {};
+
+  if (!params.id) {
+    throw new ArgumentError('The organization ID passed in params cannot be null or undefined');
+  }
+  if (typeof params.id !== 'string') {
+    throw new ArgumentError('The organization ID has to be a string');
+  }
+
+  if (!params.connection_id) {
+    throw new ArgumentError('The connection ID passed in params cannot be null or undefined');
+  }
+  if (typeof params.connection_id !== 'string') {
+    throw new ArgumentError('The connection ID has to be a string');
+  }
+
+  if (cb && cb instanceof Function) {
+    return this.connections.patch(params, data, cb);
+  }
+
+  return this.connections.patch(params, data);
+};
+
+/**
+ **** Organization Members
+ */
+
+/**
+ * Get Members in a Organization
+ *
+ * @method    getMembers
+ * @memberOf  module:management.OrganizationsManager.prototype
+ *
+ * @example
+ * var params = {id : 'ORGANIZATION_ID'}
+ * @example <caption>
+ *   This method takes an organization ID and returns the members in an Organization
+ * </caption>
+ *
+ * management.organizations.getMembers( {id : 'ORGANIZATION_ID'}, function (err, members) {
+ *   console.log(members);
+ * });
+ *
+ * @param   {String}    [params.id]   Organization ID
+ * @param   {Function}  [cb]          Callback function.
+ *
+ * @return  {Promise|undefined}
+ */
+OrganizationsManager.prototype.getMembers = function(params, callback) {
+  return this.members.getAll(params, callback);
+};
+
+/**
+ * Add members in an organization
+ *
+ * @method    addMembers
+ * @memberOf  module:management.OrganizationsManager.prototype
+ *
+ * @example
+ * var params =  { id :'ORGANIZATION_ID'};
+ * var data = { members: [ 'USER_ID1', 'USER_ID2' ] }
+ * management.organizations.addMembers(params, data, function (err) {
+ *   if (err) {
+ *     // Handle error.
+ *   }
+ * });
+ *
+ * @param   {String}    params.id             ID of the Organization.
+ * @param   {Object}    data                  add members data
+ * @param   {Array}     data.members          Array of user IDs
+ * @param   {Function}  [cb]                  Callback function.
+ *
+ * @return  {Promise|undefined}
+ */
+OrganizationsManager.prototype.addMembers = function(params, data, cb) {
+  data = data || {};
+  params = params || {};
+
+  if (!params.id) {
+    throw new ArgumentError('The organization ID passed in params cannot be null or undefined');
+  }
+  if (typeof params.id !== 'string') {
+    throw new ArgumentError('The organization ID has to be a string');
+  }
+
+  if (cb && cb instanceof Function) {
+    return this.members.create(params, data, cb);
+  }
+
+  return this.members.create(params, data);
+};
+
+/**
+ * Remove members from an organization
+ *
+ * @method    removeMembers
+ * @memberOf  module:management.OrganizationsManager.prototype
+ *
+ * @example
+ * var params =  { id :'ORGANIZATION_ID' };
+ * var data = { members: [ 'USER_ID1', 'USER_ID2' ] }
+ *
+ * management.organizations.removeMembers(params, data, function (err) {
+ *   if (err) {
+ *     // Handle error.
+ *   }
+ * });
+ *
+ * @param   {String}    params.id             ID of the Organization.
+ * @param   {Object}    data                  add members data
+ * @param   {Array}     data.members          Array of user IDs
+ * @param   {Function}  [cb]                  Callback function.
+ *
+ * @return  {Promise|undefined}
+ */
+OrganizationsManager.prototype.removeMembers = function(params, data, cb) {
+  data = data || {};
+  params = params || {};
+
+  if (!params.id) {
+    throw new ArgumentError('The organization ID passed in params cannot be null or undefined');
+  }
+  if (typeof params.id !== 'string') {
+    throw new ArgumentError('The organization ID has to be a string');
+  }
+
+  if (cb && cb instanceof Function) {
+    return this.members.delete(params, data, cb);
+  }
+
+  return this.members.delete(params, data);
+};
+
+/**
+ **** Organization Invites
+ */
+
+/**
+ * Get Invites in a Organization
+ *
+ * @method   getInvitations
+ * @memberOf  module:management.OrganizationsManager.prototype
+ *
+ * @example
+ * var params = {id : 'ORGANIZATION_ID'}
+ * @example <caption>
+ *   This method takes an organization ID and returns the invites in an Organization
+ * </caption>
+ *
+ * management.organizations.getInvitations( {id : 'ORGANIZATION_ID'}, function (err, invites) {
+ *   console.log(invites);
+ * });
+ *
+ * @param   {String}    [params.id]   Organization ID
+ * @param   {Function}  [cb]                Callback function.
+ *
+ * @return  {Promise|undefined}
+ */
+OrganizationsManager.prototype.getInvitations = function(params, callback) {
+  return this.invitations.getAll(params, callback);
+};
+
+/**
+ * Get an Invitation in a Organization
+ *
+ * @method    getInvitation
+ * @memberOf  module:management.OrganizationsManager.prototype
+ *
+ * @example
+ * var params = {id : 'ORGANIZATION_ID', invitation_id: 'INVITATION_ID'}
+ * @example <caption>
+ *   This methods takes the organization ID and user ID and returns the invitation
+ * </caption>
+ *
+ * management.organizations.getInvitation({id : 'ORGANIZATION_ID', invitation_id: 'INVITATION_ID'}, function (err, invite) {
+ *   console.log(invite);
+ * });
+ *
+ * @param   {String}    [organization_id]   Organization ID
+ * @param   {Function}  [cb]                Callback function.
+ *
+ * @return  {Promise|undefined}
+ */
+OrganizationsManager.prototype.getInvitation = function(params, callback) {
+  if (!params.id) {
+    throw new ArgumentError('The organization ID passed in params cannot be null or undefined');
+  }
+  if (typeof params.id !== 'string') {
+    throw new ArgumentError('The organization ID has to be a string');
+  }
+
+  if (!params.invitation_id) {
+    throw new ArgumentError('The invitation ID passed in params cannot be null or undefined');
+  }
+  if (typeof params.invitation_id !== 'string') {
+    throw new ArgumentError('The invitation ID has to be a string');
+  }
+
+  return this.invitations.get(params, callback);
+};
+
+/**
+ * Create an invitation in an organization
+ *
+ * @method    createInvitation
+ * @memberOf  module:management.OrganizationsManager.prototype
+ *
+ * @example
+ * var params =  { id :'ORGANIZATION_ID'};
+ * var data = {
+ *   client_id: CLIENT_ID,
+ *   invitee: { email: 'invitee@example.com' },
+ *   inviter: { name: 'John Doe' }
+ * };
+ *
+ * management.organizations.createInvitation(params, data, function (err) {
+ *   if (err) {
+ *     // Handle error.
+ *   }
+ * });
+ *
+ * @param   {String}  params.id                     ID of the Organization.
+ * @param   {Array}   data                          Invitation data
+ * @param   {Object}  data.inviter                  The person who is sending the invite.
+ * @param   {String}  data.inviter.name             Name of the person who is sending the invite
+ * @param   {Object}  data.invitee                  Invitee to whom invitation is intended for
+ * @param   {Object}  data.invitee.email            Email of the invitee to whom invitation is intended for
+ * @param   {String}  data.client_id                Auth0 client used to resolve the default application login URI. This endpoint must expect &invitation=... and &organization=... parameters (added by API2) to continue the flow with /authorize. If client_id  does not have configured login URI, use the tenant level default login route if configured, otherwise return 400
+ * @param   {String}  [data.connection_id]          Force user to authenticate against a specific identity provider.
+ * @param   {Object}  [data.app_metadata]           Application metadata to be assigned to the user after accept the invitation.
+ * @param   {Object}  [data.user_metadata]          User metadata to be assigned to the user after accept the invitation.
+ * @param   {Array}   [data.roles]                  List of roles to be assigned to the user
+ * @param   {Number}  [data.ttl_sec]                Number of seconds for which the invitation is valid before expiration. If unspecified or set to 0, this value defaults to 604800 seconds (7 days).  Upper limit on ttl_sec is 30 days.
+ * @param   {Boolean} [data.send_invitation_email]  Whether the user will receive an invitation email (true) or no email (false). Default is true.
+ * @param   {Function}  [cb]                        Callback function.
+ *
+ * @return  {Promise|undefined}
+ */
+OrganizationsManager.prototype.createInvitation = function(params, data, cb) {
+  data = data || [];
+  params = params || {};
+
+  if (!params.id) {
+    throw new ArgumentError('The organization ID passed in params cannot be null or undefined');
+  }
+  if (typeof params.id !== 'string') {
+    throw new ArgumentError('The organization ID has to be a string');
+  }
+
+  if (cb && cb instanceof Function) {
+    return this.invitations.create(params, data, cb);
+  }
+
+  return this.invitations.create(params, data);
+};
+
+/**
+ * Delete an invitation from an organization
+ *
+ * @method    deleteInvitation
+ * @memberOf  module:management.OrganizationsManager.prototype
+ *
+ * @example
+ * var params =  { id :'ORGANIZATION_ID', invitation_id: 'INVITATION_ID };
+ *
+ * management.organizations.deleteInvitation(params, function (err) {
+ *   if (err) {
+ *     // Handle error.
+ *   }
+ * });
+ *
+ * @param   {String}    params.id             ID of the Organization.
+ * @param   {String}    params.invitation_id  Invitation ID
+ * @param   {Function}  [cb]                  Callback function.
+ *
+ * @return  {Promise|undefined}
+ */
+OrganizationsManager.prototype.deleteInvitation = function(params, cb) {
+  params = params || {};
+
+  if (!params.id) {
+    throw new ArgumentError('The organization ID passed in params cannot be null or undefined');
+  }
+  if (typeof params.id !== 'string') {
+    throw new ArgumentError('The organization ID has to be a string');
+  }
+
+  if (!params.invitation_id) {
+    throw new ArgumentError('The invitation ID passed in params cannot be null or undefined');
+  }
+  if (typeof params.invitation_id !== 'string') {
+    throw new ArgumentError('The invitation ID has to be a string');
+  }
+
+  if (cb && cb instanceof Function) {
+    return this.invitations.delete(params, {}, cb);
+  }
+
+  return this.invitations.delete(params, {});
+};
+
+/**
+ **** Organization Roles Membership
+ */
+
+/**
+ * Get Roles from a Member in a Organization
+ *
+ * @method    getMemberRoles
+ * @memberOf  module:management.OrganizationsManager.prototype
+ *
+ * @example
+ * var params = {id : 'ORGANIZATION_ID', user_id: 'user_id'}
+ * @example <caption>
+ *   This methods takes the organization ID and user ID and returns the roles
+ * </caption>
+ *
+ * management.organizations.getMemberRoles( {id : 'ORGANIZATION_ID', user_id: 'user_id'}, function (err, roles) {
+ *   console.log(roles);
+ * });
+ *
+ * @param   {String}    params.id           ID of the Organization.
+ * @param   {String}    params.user_id      ID of the user.
+ * @param   {Function}  [cb]                Callback function.
+ *
+ * @return  {Promise|undefined}
+ */
+OrganizationsManager.prototype.getMemberRoles = function(params, callback) {
+  return this.roles.getAll(params, callback);
+};
+
+/**
+ * Add a Role to a Member in an organization
+ *
+ * @method    addMemberRoles
+ * @memberOf  module:management.OrganizationsManager.prototype
+ *
+ * @example
+ * var params =  {id : 'ORGANIZATION_ID', user_id: 'user_id'};
+ * var data = { roles: ["ROLE_ID_1", "ROLE_ID_2"]}
+ *
+ * management.organizations.addMemberRoles(params, data, function (err) {
+ *   if (err) {
+ *     // Handle error.
+ *   }
+ * });
+ *
+ * @param   {String}    params.id             ID of the Organization.
+ * @param   {String}    params.user_id        ID of the user.
+ * @param   {Object}    data                  Add member roles data.
+ * @param   {Array}     data.roles            Array of role IDs.
+ * @param   {Function}  [cb]                  Callback function.
+ *
+ * @return  {Promise|undefined}
+ */
+OrganizationsManager.prototype.addMemberRoles = function(params, data, cb) {
+  data = data || {};
+  params = params || {};
+
+  if (!params.id) {
+    throw new ArgumentError('The organization ID passed in params cannot be null or undefined');
+  }
+  if (typeof params.id !== 'string') {
+    throw new ArgumentError('The organization ID has to be a string');
+  }
+
+  if (!params.user_id) {
+    throw new ArgumentError('The user ID passed in params cannot be null or undefined');
+  }
+  if (typeof params.user_id !== 'string') {
+    throw new ArgumentError('The user ID has to be a string');
+  }
+
+  if (cb && cb instanceof Function) {
+    return this.roles.create(params, data, cb);
+  }
+
+  return this.roles.create(params, data);
+};
+
+/**
+ * Remove Roles from a Member of an organization
+ *
+ * @method    removeMemberRoles
+ * @memberOf  module:management.OrganizationsManager.prototype
+ *
+ * @example
+ * var params =  { id :'ORGANIZATION_ID', user_id: 'USER_ID };
+ * var data = { roles: ["ROLE_ID_1", "ROLE_ID_2"]}
+ *
+ * management.organizations.removeMemberRoles(params, data, function (err) {
+ *   if (err) {
+ *     // Handle error.
+ *   }
+ * });
+ *
+ * @param   {String}    params.id             ID of the Organization.
+ * @param   {String}    params.user_id        Id of the User
+ * @param   {Object}    data                  Remove member roles data.
+ * @param   {Array}     data.roles            Array of role IDs.
+ * @param   {Function}  [cb]                  Callback function.
+ *
+ * @return  {Promise|undefined}
+ */
+OrganizationsManager.prototype.removeMemberRoles = function(params, data, cb) {
+  data = data || {};
+  params = params || {};
+
+  if (!params.id) {
+    throw new ArgumentError('The organization ID passed in params cannot be null or undefined');
+  }
+  if (typeof params.id !== 'string') {
+    throw new ArgumentError('The organization ID has to be a string');
+  }
+
+  if (!params.user_id) {
+    throw new ArgumentError('The user ID passed in params cannot be null or undefined');
+  }
+  if (typeof params.user_id !== 'string') {
+    throw new ArgumentError('The user ID has to be a string');
+  }
+
+  if (cb && cb instanceof Function) {
+    return this.roles.delete(params, data, cb);
+  }
+
+  return this.roles.delete(params, data);
+};
+
+module.exports = OrganizationsManager;
diff --git a/src/management/TicketsManager.js b/src/management/TicketsManager.js
index a037d82b0..1614a5717 100644
--- a/src/management/TicketsManager.js
+++ b/src/management/TicketsManager.js
@@ -66,6 +66,16 @@ var TicketsManager = function(options) {
  *   }
  * });
  *
+ * @param   {Object}  data
+ * @param   {String}  [data.result_url] URL the user will be redirected to once ticket is used.
+ * @param   {String}  [data.user_id] user_id for whom the ticket should be created. (Conflicts with: connection_id, email)
+ * @param   {String}  [data.client_id] ID of the client.
+ * @param   {String}  [data.organization_id] ID of the organization.
+ * @param   {String}  [data.connection_id] ID of the connection.
+ * @param   {Integer} [data.ttl_sec] Number of seconds for which the ticket is valid before expiration.
+ * @param   {String}  [data.email] Email of the user. (Requires: connection_id)
+ * @param   {Boolean} [data.mark_email_as_verified] Whether to set the email_verified attribute to true (true) or whether it should not be updated (false).
+ * @param   {Boolean} [data.includeEmailInRedirect] Whether to include the email address as part of the returnUrl in the reset_email (true), or not (false).
  * @param   {Function}  [cb]  Callback function.
  * @return  {Promise}
  */
@@ -106,6 +116,8 @@ TicketsManager.prototype.changePassword = function(data, cb) {
  * @param   {Object}  [data.identity] Used to verify secondary, federated, and passwordless-email identities.
  * @param   {String}  data.identity.user_id user_id of the identity.
  * @param   {String}  data.identity.provider provider of the identity.
+ * @param   {String}  [data.client_id] client ID.
+ * @param   {String}  [data.organization_id] organization ID.
  * @param   {Function}  [cb]  Callback function.
  * @return  {Promise}
  */
diff --git a/src/management/UsersManager.js b/src/management/UsersManager.js
index a9c18ff0f..967509f42 100644
--- a/src/management/UsersManager.js
+++ b/src/management/UsersManager.js
@@ -161,6 +161,13 @@ var UsersManager = function(options) {
     options.tokenProvider
   );
   this.permissions = new RetryRestClient(userPermissionsClient, options.retry);
+
+  var organizationsClient = new Auth0RestClient(
+    options.baseUrl + '/users/:id/organizations',
+    clientOptions,
+    options.tokenProvider
+  );
+  this.organizations = new RetryRestClient(organizationsClient, options.retry);
 };
 
 /**
@@ -929,4 +936,25 @@ UsersManager.prototype.removePermissions = function(params, data, cb) {
   return this.permissions.delete(query, data);
 };
 
+/**
+ * Get a list of organizations for a user.
+ *
+ * @method    getUserOrganizations
+ * @memberOf  module:management.UsersManager.prototype
+ *
+ * @example
+ * management.users.getUserOrganizations({ id: USER_ID }, function (err, orgs) {
+ *   console.log(orgs);
+ * });
+ *
+ * @param   {Object}    data      The user data object.
+ * @param   {String}    data.id   The user id.
+ * @param   {Function}  [cb]      Callback function.
+ *
+ * @return  {Promise|undefined}
+ */
+UsersManager.prototype.getUserOrganizations = function() {
+  return this.organizations.getAll.apply(this.organizations, arguments);
+};
+
 module.exports = UsersManager;
diff --git a/src/management/index.js b/src/management/index.js
index d504c7ff4..e71bc054b 100644
--- a/src/management/index.js
+++ b/src/management/index.js
@@ -34,6 +34,7 @@ var HooksManager = require('./HooksManager');
 var BrandingManager = require('./BrandingManager');
 var MigrationsManager = require('./MigrationsManager');
 var PromptsManager = require('./PromptsManager');
+var OrganizationsManager = require('./OrganizationsManager');
 
 var BASE_URL_FORMAT = 'https://%s/api/v2';
 var MANAGEMENT_API_AUD_FORMAT = 'https://%s/api/v2/';
@@ -350,6 +351,13 @@ var ManagementClient = function(options) {
    * @type {PromptsManager}
    */
   this.prompts = new PromptsManager(managerOptions);
+
+  /**
+   * Organizations Manager
+   *
+   * @type {OrganizationsManager}
+   */
+  this.organizations = new OrganizationsManager(managerOptions);
 };
 
 /**


Test patch:
diff --git a/test/management/organizations.tests.js b/test/management/organizations.tests.js
new file mode 100644
index 000000000..2bbc28616
--- /dev/null
+++ b/test/management/organizations.tests.js
@@ -0,0 +1,1766 @@
+var expect = require('chai').expect;
+var nock = require('nock');
+
+var SRC_DIR = '../../src';
+var API_URL = 'https://tenant.auth0.com';
+
+var OrganizationsManager = require(SRC_DIR + '/management/OrganizationsManager');
+var ArgumentError = require('rest-facade').ArgumentError;
+
+describe('OrganizationsManager', function() {
+  before(function() {
+    this.token = 'TOKEN';
+    this.organizations = new OrganizationsManager({
+      headers: { authorization: 'Bearer ' + this.token },
+      baseUrl: API_URL
+    });
+  });
+
+  describe('instance', function() {
+    var methods = [
+      'getByID',
+      'getByName',
+      'getAll',
+      'create',
+      'update',
+      'delete',
+      'getEnabledConnections',
+      'getEnabledConnection',
+      'addEnabledConnection',
+      'updateEnabledConnection',
+      'removeEnabledConnection',
+      'getMembers',
+      'addMembers',
+      'removeMembers',
+      'getMemberRoles',
+      'addMemberRoles',
+      'removeMemberRoles',
+      'getInvitations',
+      'getInvitation',
+      'createInvitation',
+      'deleteInvitation'
+    ];
+
+    methods.forEach(function(method) {
+      it('should have a ' + method + ' method', function() {
+        expect(this.organizations[method]).to.exist.to.be.an.instanceOf(Function);
+      });
+    });
+  });
+
+  describe('#constructor', function() {
+    it('should error when no options are provided', function() {
+      expect(OrganizationsManager).to.throw(ArgumentError, 'Must provide manager options');
+    });
+
+    it('should throw an error when no base URL is provided', function() {
+      var client = OrganizationsManager.bind(null, {});
+
+      expect(client).to.throw(ArgumentError, 'Must provide a base URL for the API');
+    });
+
+    it('should throw an error when the base URL is invalid', function() {
+      var client = OrganizationsManager.bind(null, { baseUrl: '' });
+
+      expect(client).to.throw(ArgumentError, 'The provided base URL is invalid');
+    });
+  });
+
+  describe('#getAll', function() {
+    beforeEach(function() {
+      this.request = nock(API_URL)
+        .get('/organizations')
+        .reply(200);
+    });
+
+    it('should accept a callback', function(done) {
+      this.organizations.getAll(function() {
+        done();
+      });
+    });
+
+    it('should return a promise if no callback is given', function(done) {
+      this.organizations
+        .getAll()
+        .then(done.bind(null, null))
+        .catch(done.bind(null, null));
+    });
+
+    it('should pass any errors to the promise catch handler', function(done) {
+      nock.cleanAll();
+
+      var request = nock(API_URL)
+        .get('/organizations')
+        .reply(500);
+
+      this.organizations.getAll().catch(function(err) {
+        expect(err).to.exist;
+        done();
+      });
+    });
+
+    it('should pass the body of the response to the "then" handler', function(done) {
+      nock.cleanAll();
+
+      var data = [{ test: true }];
+      var request = nock(API_URL)
+        .get('/organizations')
+        .reply(200, data);
+
+      this.organizations.getAll().then(function(credentials) {
+        expect(credentials).to.be.an.instanceOf(Array);
+
+        expect(credentials.length).to.equal(data.length);
+
+        expect(credentials[0].test).to.equal(data[0].test);
+
+        done();
+      });
+    });
+
+    it('should perform a GET request to /api/v2/organizations', function(done) {
+      var request = this.request;
+
+      this.organizations.getAll().then(function() {
+        expect(request.isDone()).to.be.true;
+        done();
+      });
+    });
+
+    it('should include the token in the Authorization header', function(done) {
+      nock.cleanAll();
+
+      var request = nock(API_URL)
+        .get('/organizations')
+        .matchHeader('Authorization', 'Bearer ' + this.token)
+        .reply(200);
+
+      this.organizations.getAll().then(function() {
+        expect(request.isDone()).to.be.true;
+        done();
+      });
+    });
+
+    it('should pass the parameters in the query-string', function(done) {
+      nock.cleanAll();
+
+      var params = {
+        include_fields: true,
+        fields: 'test'
+      };
+      var request = nock(API_URL)
+        .get('/organizations')
+        .query(params)
+        .reply(200);
+
+      this.organizations.getAll(params).then(function() {
+        expect(request.isDone()).to.be.true;
+
+        done();
+      });
+    });
+  });
+
+  describe('#getByID', function() {
+    beforeEach(function() {
+      this.data = {
+        id: 'org_123456',
+        name: 'organizations',
+        display_name: 'My organization'
+      };
+
+      this.request = nock(API_URL)
+        .get('/organizations/' + this.data.id)
+        .reply(200, this.data);
+    });
+
+    it('should accept a callback', function(done) {
+      var params = { id: this.data.id };
+
+      this.organizations.getByID(params, done.bind(null, null));
+    });
+
+    it('should return a promise if no callback is given', function(done) {
+      this.organizations
+        .getByID({ id: this.data.id })
+        .then(done.bind(null, null))
+        .catch(done.bind(null, null));
+    });
+
+    it('should perform a GET request to /api/v2/organizations/:id', function(done) {
+      var request = this.request;
+
+      this.organizations.getByID({ id: this.data.id }).then(function() {
+        expect(request.isDone()).to.be.true;
+
+        done();
+      });
+    });
+
+    it('should pass any errors to the promise catch handler', function(done) {
+      nock.cleanAll();
+
+      var request = nock(API_URL)
+        .get('/organizations/' + this.data.id)
+        .reply(500);
+
+      this.organizations.getByID({ id: this.data.id }).catch(function(err) {
+        expect(err).to.exist;
+
+        done();
+      });
+    });
+
+    it('should include the token in the Authorization header', function(done) {
+      nock.cleanAll();
+
+      var request = nock(API_URL)
+        .get('/organizations/' + this.data.id)
+        .matchHeader('Authorization', 'Bearer ' + this.token)
+        .reply(200);
+
+      this.organizations.getByID({ id: this.data.id }).then(function() {
+        expect(request.isDone()).to.be.true;
+
+        done();
+      });
+    });
+  });
+
+  describe('#getByName', function() {
+    beforeEach(function() {
+      this.data = {
+        id: 'org_123456',
+        name: 'organizations',
+        display_name: 'My organization'
+      };
+
+      this.request = nock(API_URL)
+        .get('/organizations/name/' + this.data.name)
+        .reply(200, this.data);
+    });
+
+    it('should accept a callback', function(done) {
+      var params = { name: this.data.name };
+
+      this.organizations.getByName(params, done.bind(null, null));
+    });
+
+    it('should return a promise if no callback is given', function(done) {
+      this.organizations
+        .getByName({ name: this.data.name })
+        .then(done.bind(null, null))
+        .catch(done.bind(null, null));
+    });
+
+    it('should perform a GET request to /api/v2/organizations/name/:name', function(done) {
+      var request = this.request;
+
+      this.organizations.getByName({ name: this.data.name }).then(function() {
+        expect(request.isDone()).to.be.true;
+
+        done();
+      });
+    });
+
+    it('should pass any errors to the promise catch handler', function(done) {
+      nock.cleanAll();
+
+      var request = nock(API_URL)
+        .get('/organizations/' + this.data.name)
+        .reply(500);
+
+      this.organizations.getByName({ name: this.data.name }).catch(function(err) {
+        expect(err).to.exist;
+
+        done();
+      });
+    });
+
+    it('should include the token in the Authorization header', function(done) {
+      nock.cleanAll();
+
+      var request = nock(API_URL)
+        .get('/organizations/name/' + this.data.name)
+        .matchHeader('Authorization', 'Bearer ' + this.token)
+        .reply(200);
+
+      this.organizations.getByName({ name: this.data.name }).then(function() {
+        expect(request.isDone()).to.be.true;
+
+        done();
+      });
+    });
+  });
+
+  describe('#create', function() {
+    var data = {
+      id: 'org_123',
+      name: 'org_name',
+      display_name: 'My Organization'
+    };
+
+    beforeEach(function() {
+      this.request = nock(API_URL)
+        .post('/organizations')
+        .reply(200);
+    });
+
+    it('should accept a callback', function(done) {
+      this.organizations.create(data, function() {
+        done();
+      });
+    });
+
+    it('should return a promise if no callback is given', function(done) {
+      this.organizations
+        .create(data)
+        .then(done.bind(null, null))
+        .catch(done.bind(null, null));
+    });
+
+    it('should pass any errors to the promise catch handler', function(done) {
+      nock.cleanAll();
+
+      var request = nock(API_URL)
+        .post('/organizations')
+        .reply(500);
+
+      this.organizations.create(data).catch(function(err) {
+        expect(err).to.exist;
+
+        done();
+      });
+    });
+
+    it('should perform a POST request to /api/v2/organizations', function(done) {
+      var request = this.request;
+
+      this.organizations.create(data).then(function() {
+        expect(request.isDone()).to.be.true;
+
+        done();
+      });
+    });
+
+    it('should pass the data in the body of the request', function(done) {
+      nock.cleanAll();
+
+      var request = nock(API_URL)
+        .post('/organizations', data)
+        .reply(200);
+
+      this.organizations.create(data).then(function() {
+        expect(request.isDone()).to.be.true;
+
+        done();
+      });
+    });
+
+    it('should include the token in the Authorization header', function(done) {
+      nock.cleanAll();
+
+      var request = nock(API_URL)
+        .post('/organizations')
+        .matchHeader('Authorization', 'Bearer ' + this.token)
+        .reply(200);
+
+      this.organizations.create(data).then(function() {
+        expect(request.isDone()).to.be.true;
+
+        done();
+      });
+    });
+  });
+
+  describe('#update', function() {
+    beforeEach(function() {
+      this.data = { id: 'org_123' };
+
+      this.request = nock(API_URL)
+        .patch('/organizations/' + this.data.id)
+        .reply(200, this.data);
+    });
+
+    it('should accept a callback', function(done) {
+      this.organizations.update({ id: 'org_123' }, {}, done.bind(null, null));
+    });
+
+    it('should return a promise if no callback is given', function(done) {
+      this.organizations
+        .update({ id: 'org_123' }, {})
+        .then(done.bind(null, null))
+        .catch(done.bind(null, null));
+    });
+
+    it('should perform a PATCH request to /api/v2/organizations/org_123', function(done) {
+      var request = this.request;
+
+      this.organizations.update({ id: 'org_123' }, {}).then(function() {
+        expect(request.isDone()).to.be.true;
+
+        done();
+      });
+    });
+
+    it('should include the new data in the body of the request', function(done) {
+      nock.cleanAll();
+
+      var request = nock(API_URL)
+        .patch('/organizations/' + this.data.id, this.data)
+        .reply(200);
+
+      this.organizations.update({ id: 'org_123' }, this.data).then(function() {
+        expect(request.isDone()).to.be.true;
+
+        done();
+      });
+    });
+
+    it('should pass any errors to the promise catch handler', function(done) {
+      nock.cleanAll();
+
+      var request = nock(API_URL)
+        .patch('/organizations/' + this.data.id)
+        .reply(500);
+
+      this.organizations.update({ id: this.data.id }, this.data).catch(function(err) {
+        expect(err).to.exist;
+
+        done();
+      });
+    });
+  });
+
+  describe('#delete', function() {
+    var id = 'rol_ID';
+
+    beforeEach(function() {
+      this.request = nock(API_URL)
+        .delete('/organizations/' + id)
+        .reply(200);
+    });
+
+    it('should accept a callback', function(done) {
+      this.organizations.delete({ id: id }, done.bind(null, null));
+    });
+
+    it('should return a promise when no callback is given', function(done) {
+      this.organizations.delete({ id: id }).then(done.bind(null, null));
+    });
+
+    it('should perform a delete request to /organizations/' + id, function(done) {
+      var request = this.request;
+
+      this.organizations.delete({ id: id }).then(function() {
+        expect(request.isDone()).to.be.true;
+
+        done();
+      });
+    });
+
+    it('should pass any errors to the promise catch handler', function(done) {
+      nock.cleanAll();
+
+      var request = nock(API_URL)
+        .delete('/organizations/' + id)
+        .reply(500);
+
+      this.organizations.delete({ id: id }).catch(function(err) {
+        expect(err).to.exist;
+
+        done();
+      });
+    });
+
+    it('should include the token in the authorization header', function(done) {
+      nock.cleanAll();
+
+      var request = nock(API_URL)
+        .delete('/organizations/' + id)
+        .matchHeader('authorization', 'Bearer ' + this.token)
+        .reply(200);
+
+      this.organizations.delete({ id: id }).then(function() {
+        expect(request.isDone()).to.be.true;
+
+        done();
+      });
+    });
+  });
+
+  //// Connections
+  describe('#getEnabledConnections', function() {
+    var data = {
+      id: 'org_id'
+    };
+
+    beforeEach(function() {
+      this.request = nock(API_URL)
+        .get('/organizations/' + data.id + '/enabled_connections')
+        .reply(200);
+    });
+
+    it('should accept a callback', function(done) {
+      this.organizations.getEnabledConnections(data, done.bind(null, null));
+    });
+
+    it('should return a promise when no callback is given', function(done) {
+      this.organizations.getEnabledConnections(data).then(done.bind(null, null));
+    });
+
+    it('should perform a GET request to /api/v2/organizations/org_id/enabled_connections', function(done) {
+      var request = this.request;
+
+      this.organizations.getEnabledConnections(data).then(function() {
+        expect(request.isDone()).to.be.true;
+
+        done();
+      });
+    });
+
+    it('should pass any errors to the promise catch handler', function(done) {
+      nock.cleanAll();
+
+      var request = nock(API_URL)
+        .get('/organizations/' + data.id + '/enabled_connections')
+        .reply(500);
+
+      this.organizations.getEnabledConnections(data).catch(function(err) {
+        expect(err).to.exist;
+
+        done();
+      });
+    });
+
+    it('should include the token in the authorization header', function(done) {
+      nock.cleanAll();
+
+      var request = nock(API_URL)
+        .get('/organizations/' + data.id + '/enabled_connections')
+        .matchHeader('authorization', 'Bearer ' + this.token)
+        .reply(200);
+
+      this.organizations.getEnabledConnections(data).then(function() {
+        expect(request.isDone()).to.be.true;
+
+        done();
+      });
+    });
+  });
+
+  describe('#getEnabledConnection', function() {
+    var data = {
+      id: 'org_id',
+      connection_id: 'conn_id'
+    };
+
+    beforeEach(function() {
+      this.request = nock(API_URL)
+        .get('/organizations/' + data.id + '/enabled_connections/' + data.connection_id)
+        .reply(200);
+    });
+
+    it('should accept a callback', function(done) {
+      this.organizations.getEnabledConnection(data, done.bind(null, null));
+    });
+
+    it('should return a promise when no callback is given', function(done) {
+      this.organizations.getEnabledConnection(data).then(done.bind(null, null));
+    });
+
+    it('should perform a GET request to /api/v2/organizations/rol_ID/enabled_connections/con_id', function(done) {
+      var request = this.request;
+
+      this.organizations.getEnabledConnection(data).then(function() {
+        expect(request.isDone()).to.be.true;
+
+        done();
+      });
+    });
+
+    it('should pass any errors to the promise catch handler', function(done) {
+      nock.cleanAll();
+
+      var request = nock(API_URL)
+        .get('/organizations/' + data.id + '/enabled_connections/' + data.connection_id)
+        .reply(500);
+
+      this.organizations.getEnabledConnection(data).catch(function(err) {
+        expect(err).to.exist;
+
+        done();
+      });
+    });
+
+    it('should include the token in the authorization header', function(done) {
+      nock.cleanAll();
+
+      var request = nock(API_URL)
+        .get('/organizations/' + data.id + '/enabled_connections/' + data.connection_id)
+        .matchHeader('authorization', 'Bearer ' + this.token)
+        .reply(200);
+
+      this.organizations.getEnabledConnection(data).then(function() {
+        expect(request.isDone()).to.be.true;
+
+        done();
+      });
+    });
+  });
+
+  describe('#addEnabledConnection', function() {
+    beforeEach(function() {
+      this.data = {
+        id: 'org_123'
+      };
+      this.body = { connection_id: '123', assign_membership_on_login: false };
+
+      this.request = nock(API_URL)
+        .post('/organizations/' + this.data.id + '/enabled_connections')
+        .reply(200);
+    });
+
+    it('should accept a callback', function(done) {
+      this.organizations.addEnabledConnection(this.data, {}, function() {
+        done();
+      });
+    });
+
+    it('should return a promise if no callback is given', function(done) {
+      this.organizations
+        .addEnabledConnection(this.data, {})
+        .then(done.bind(null, null))
+        .catch(done.bind(null, null));
+    });
+
+    it('should pass any errors to the promise catch handler', function(done) {
+      nock.cleanAll();
+
+      var request = nock(API_URL)
+        .post('/organizations/' + this.data.id + '/enabled_connections')
+        .reply(500);
+
+      this.organizations.addEnabledConnection(this.data, {}).catch(function(err) {
+        expect(err).to.exist;
+
+        done();
+      });
+    });
+
+    it('should perform a POST request to /api/v2/organizations/org_id/enabled_connections', function(done) {
+      var request = this.request;
+
+      this.organizations.addEnabledConnection(this.data, this.body).then(function() {
+        expect(request.isDone()).to.be.true;
+
+        done();
+      });
+    });
+
+    it('should return error when id is not sent', function() {
+      var _this = this;
+      expect(function() {
+        _this.organizations.addEnabledConnection({ id: null }, {}, function() {});
+      }).to.throw('The organization ID passed in params cannot be null or undefined');
+    });
+
+    it('should return error when id is not a string', function() {
+      var _this = this;
+      expect(function() {
+        _this.organizations.addEnabledConnection({ id: 123 }, {}, function() {});
+      }).to.throw('The organization ID has to be a string');
+    });
+
+    it('should pass the data in the body of the request', function(done) {
+      nock.cleanAll();
+
+      var request = nock(API_URL)
+        .post('/organizations/' + this.data.id + '/enabled_connections', this.body)
+        .reply(200);
+
+      this.organizations.addEnabledConnection(this.data, this.body).then(function() {
+        expect(request.isDone()).to.be.true;
+
+        done();
+      });
+    });
+
+    it('should include the token in the Authorization header', function(done) {
+      nock.cleanAll();
+
+      var request = nock(API_URL)
+        .post('/organizations/' + this.data.id + '/enabled_connections')
+        .matchHeader('Authorization', 'Bearer ' + this.token)
+        .reply(200);
+
+      this.organizations.addEnabledConnection(this.data, {}).then(function() {
+        expect(request.isDone()).to.be.true;
+
+        done();
+      });
+    });
+  });
+
+  describe('#updateEnabledConnection', function() {
+    beforeEach(function() {
+      this.data = {
+        id: 'org_123',
+        connection_id: '123'
+      };
+      this.body = { assign_membership_on_login: false };
+
+      this.request = nock(API_URL)
+        .patch('/organizations/' + this.data.id + '/enabled_connections/' + this.data.connection_id)
+        .reply(200);
+    });
+
+    it('should accept a callback', function(done) {
+      this.organizations.updateEnabledConnection(this.data, this.body, function() {
+        done();
+      });
+    });
+
+    it('should return a promise if no callback is given', function(done) {
+      this.organizations
+        .updateEnabledConnection(this.data, this.body)
+        .then(done.bind(null, null))
+        .catch(done.bind(null, null));
+    });
+
+    it('should pass any errors to the promise catch handler', function(done) {
+      nock.cleanAll();
+
+      var request = nock(API_URL)
+        .patch('/organizations/' + this.data.id + '/enabled_connections/' + this.data.connection_id)
+        .reply(500);
+
+      this.organizations.updateEnabledConnection(this.data, this.body).catch(function(err) {
+        expect(err).to.exist;
+
+        done();
+      });
+    });
+
+    it('should perform a PATCH request to /api/v2/organizations/org_id/enabled_connections/conn_id', function(done) {
+      var request = this.request;
+
+      this.organizations.updateEnabledConnection(this.data, this.body).then(function() {
+        expect(request.isDone()).to.be.true;
+
+        done();
+      });
+    });
+
+    it('should return error when id is not sent', function() {
+      var _this = this;
+      expect(function() {
+        _this.organizations.updateEnabledConnection({ id: null }, {}, function() {});
+      }).to.throw('The organization ID passed in params cannot be null or undefined');
+    });
+
+    it('should return error when id is not a string', function() {
+      var _this = this;
+      expect(function() {
+        _this.organizations.updateEnabledConnection({ id: 123 }, {}, function() {});
+      }).to.throw('The organization ID has to be a string');
+    });
+
+    it('should return error when connection_id is not sent', function() {
+      var _this = this;
+      expect(function() {
+        _this.organizations.updateEnabledConnection(
+          { id: 'org_123', connection_id: null },
+          {},
+          function() {}
+        );
+      }).to.throw('The connection ID passed in params cannot be null or undefined');
+    });
+
+    it('should return error when connection_id is not a string', function() {
+      var _this = this;
+      expect(function() {
+        _this.organizations.updateEnabledConnection(
+          { id: 'org_123', connection_id: 123 },
+          {},
+          function() {}
+        );
+      }).to.throw('The connection ID has to be a string');
+    });
+
+    it('should pass the data in the body of the request', function(done) {
+      nock.cleanAll();
+
+      var request = nock(API_URL)
+        .patch(
+          '/organizations/' + this.data.id + '/enabled_connections/' + this.data.connection_id,
+          this.body
+        )
+        .reply(200);
+
+      this.organizations.updateEnabledConnection(this.data, this.body).then(function() {
+        expect(request.isDone()).to.be.true;
+
+        done();
+      });
+    });
+
+    it('should include the token in the Authorization header', function(done) {
+      nock.cleanAll();
+
+      var request = nock(API_URL)
+        .patch('/organizations/' + this.data.id + '/enabled_connections/' + this.data.connection_id)
+        .matchHeader('Authorization', 'Bearer ' + this.token)
+        .reply(200);
+
+      this.organizations.updateEnabledConnection(this.data, this.body).then(function() {
+        expect(request.isDone()).to.be.true;
+
+        done();
+      });
+    });
+  });
+
+  describe('#removeEnabledConnection', function() {
+    beforeEach(function() {
+      this.data = {
+        id: 'org_123',
+        connection_id: '123'
+      };
+
+      this.request = nock(API_URL)
+        .delete(
+          '/organizations/' + this.data.id + '/enabled_connections/' + this.data.connection_id,
+          {}
+        )
+        .reply(200);
+    });
+
+    it('should validate empty organizationId', function() {
+      var _this = this;
+      expect(function() {
+        _this.organizations.removeEnabledConnection({ id: null }, function() {});
+      }).to.throw('The organization ID passed in params cannot be null or undefined');
+    });
+
+    it('should validate empty connectionId', function() {
+      var _this = this;
+      expect(function() {
+        _this.organizations.removeEnabledConnection({ id: _this.data.id }, function() {});
+      }).to.throw('The connection ID passed in params cannot be null or undefined');
+    });
+
+    it('should validate non-string organizationId', function() {
+      var _this = this;
+      expect(function() {
+        _this.organizations.removeEnabledConnection({ id: 123 }, function() {});
+      }).to.throw('The organization ID has to be a string');
+    });
+
+    it('should validate non-string connectionId', function() {
+      var _this = this;
+      expect(function() {
+        _this.organizations.removeEnabledConnection(
+          { id: _this.data.id, connection_id: 123 },
+          function() {}
+        );
+      }).to.throw('The connection ID has to be a string');
+    });
+
+    it('should accept a callback', function(done) {
+      this.organizations.removeEnabledConnection(this.data, function() {
+        done();
+      });
+    });
+
+    it('should return a promise if no callback is given', function(done) {
+      this.organizations
+        .removeEnabledConnection(this.data)
+        .then(done.bind(null, null))
+        .catch(done.bind(null, null));
+    });
+
+    it('should pass any errors to the promise catch handler', function(done) {
+      nock.cleanAll();
+
+      var request = nock(API_URL)
+        .delete(
+          '/organizations/' + this.data.id + '/enabled_connections/' + this.data.connection_id
+        )
+        .reply(500);
+
+      this.organizations.removeEnabledConnection(this.data, {}).catch(function(err) {
+        expect(err).to.exist;
+
+        done();
+      });
+    });
+
+    it('should perform a DELETE request to /api/v2/organizations/organization_id/enabled_connections/connection_id', function(done) {
+      var request = this.request;
+
+      this.organizations.removeEnabledConnection(this.data).then(function() {
+        expect(request.isDone()).to.be.true;
+
+        done();
+      });
+    });
+
+    it('should include the token in the Authorization header', function(done) {
+      nock.cleanAll();
+
+      var request = nock(API_URL)
+        .delete(
+          '/organizations/' + this.data.id + '/enabled_connections/' + this.data.connection_id
+        )
+        .matchHeader('Authorization', 'Bearer ' + this.token)
+        .reply(200);
+
+      this.organizations.removeEnabledConnection(this.data, {}).then(function() {
+        expect(request.isDone()).to.be.true;
+
+        done();
+      });
+    });
+  });
+
+  //// Members
+  describe('#getMembers', function() {
+    var data = {
+      id: 'org_id'
+    };
+
+    beforeEach(function() {
+      this.request = nock(API_URL)
+        .get('/organizations/' + data.id + '/members')
+        .reply(200);
+    });
+
+    it('should accept a callback', function(done) {
+      this.organizations.getMembers(data, done.bind(null, null));
+    });
+
+    it('should return a promise when no callback is given', function(done) {
+      this.organizations.getMembers(data).then(done.bind(null, null));
+    });
+
+    it('should perform a GET request to /api/v2/organizations/org_ID/members', function(done) {
+      var request = this.request;
+
+      this.organizations.getMembers(data).then(function() {
+        expect(request.isDone()).to.be.true;
+
+        done();
+      });
+    });
+
+    it('should pass any errors to the promise catch handler', function(done) {
+      nock.cleanAll();
+
+      var request = nock(API_URL)
+        .get('/organizations/' + data.id + '/members')
+        .reply(500);
+
+      this.organizations.getMembers(data).catch(function(err) {
+        expect(err).to.exist;
+
+        done();
+      });
+    });
+
+    it('should include the token in the authorization header', function(done) {
+      nock.cleanAll();
+
+      var request = nock(API_URL)
+        .get('/organizations/' + data.id + '/members')
+        .matchHeader('authorization', 'Bearer ' + this.token)
+        .reply(200);
+
+      this.organizations.getMembers(data).then(function() {
+        expect(request.isDone()).to.be.true;
+
+        done();
+      });
+    });
+  });
+
+  describe('#addMembers', function() {
+    beforeEach(function() {
+      this.data = {
+        id: 'org_123'
+      };
+      this.body = ['user_id'];
+
+      this.request = nock(API_URL)
+        .post('/organizations/' + this.data.id + '/members', {})
+        .reply(200);
+    });
+
+    it('should accept a callback', function(done) {
+      this.organizations.addMembers(this.data, {}, function() {
+        done();
+      });
+    });
+
+    it('should return a promise if no callback is given', function(done) {
+      this.organizations
+        .addMembers(this.data, {})
+        .then(done.bind(null, null))
+        .catch(done.bind(null, null));
+    });
+
+    it('should pass any errors to the promise catch handler', function(done) {
+      nock.cleanAll();
+
+      var request = nock(API_URL)
+        .post('/organizations/' + this.data.id + '/members')
+        .reply(500);
+
+      this.organizations.addMembers(this.data, {}).catch(function(err) {
+        expect(err).to.exist;
+
+        done();
+      });
+    });
+
+    it('should perform a POST request to /api/v2/organizations/org_id/members', function(done) {
+      var request = this.request;
+
+      this.organizations.addMembers(this.data, {}).then(function() {
+        expect(request.isDone()).to.be.true;
+
+        done();
+      });
+    });
+
+    it('should return error when id is not sent', function() {
+      var _this = this;
+      expect(function() {
+        _this.organizations.addMembers({ id: null }, {}, function() {});
+      }).to.throw('The organization ID passed in params cannot be null or undefined');
+    });
+
+    it('should return error when id is not sent', function() {
+      var _this = this;
+      expect(function() {
+        _this.organizations.addMembers({ id: 123 }, {}, function() {});
+      }).to.throw('The organization ID has to be a string');
+    });
+
+    it('should pass the data in the body of the request', function(done) {
+      nock.cleanAll();
+
+      var request = nock(API_URL)
+        .post('/organizations/' + this.data.id + '/members', this.body)
+        .reply(200);
+
+      this.organizations.addMembers(this.data, this.body).then(function() {
+        expect(request.isDone()).to.be.true;
+
+        done();
+      });
+    });
+
+    it('should include the token in the Authorization header', function(done) {
+      nock.cleanAll();
+
+      var request = nock(API_URL)
+        .post('/organizations/' + this.data.id + '/members')
+        .matchHeader('Authorization', 'Bearer ' + this.token)
+        .reply(200);
+
+      this.organizations.addMembers(this.data, {}).then(function() {
+        expect(request.isDone()).to.be.true;
+
+        done();
+      });
+    });
+  });
+
+  describe('#removeMembers', function() {
+    beforeEach(function() {
+      this.data = {
+        id: 'org_123'
+      };
+
+      this.body = ['user_id'];
+
+      this.request = nock(API_URL)
+        .delete('/organizations/' + this.data.id + '/members', {})
+        .reply(200);
+    });
+
+    it('should validate empty organizationId', function() {
+      var _this = this;
+      expect(function() {
+        _this.organizations.removeMembers({ id: null }, this.body, function() {});
+      }).to.throw('The organization ID passed in params cannot be null or undefined');
+    });
+
+    it('should validate non-string organizationId', function() {
+      var _this = this;
+      expect(function() {
+        _this.organizations.removeMembers({ id: 123 }, _this.body, function() {});
+      }).to.throw('The organization ID has to be a string');
+    });
+
+    it('should return a promise if no callback is given', function(done) {
+      this.organizations
+        .removeMembers(this.data, this.body)
+        .then(done.bind(null, null))
+        .catch(done.bind(null, null));
+    });
+
+    it('should pass any errors to the promise catch handler', function(done) {
+      nock.cleanAll();
+
+      var request = nock(API_URL)
+        .delete('/organizations/' + this.data.id + '/members')
+        .reply(500);
+
+      this.organizations.removeMembers(this.data, this.body).catch(function(err) {
+        expect(err).to.exist;
+
+        done();
+      });
+    });
+
+    it('should perform a DELETE request to /api/v2/organizations/organization_id/members', function(done) {
+      var request = this.request;
+
+      var request = nock(API_URL)
+        .delete('/organizations/' + this.data.id + '/members', this.body)
+        .reply(200);
+
+      this.organizations.removeMembers(this.data, this.body, function() {
+        expect(request.isDone()).to.be.true;
+
+        done();
+      });
+    });
+
+    it('should include the token in the Authorization header', function(done) {
+      nock.cleanAll();
+
+      var request = nock(API_URL)
+        .delete('/organizations/' + this.data.id + '/members', this.body)
+        .matchHeader('Authorization', 'Bearer ' + this.token)
+        .reply(200);
+
+      this.organizations.removeMembers(this.data, this.body).then(function() {
+        expect(request.isDone()).to.be.true;
+
+        done();
+      });
+    });
+  });
+
+  //// Roles
+  describe('#getMemberRoles', function() {
+    var data = {
+      id: 'org_id',
+      user_id: 'user_123'
+    };
+
+    beforeEach(function() {
+      this.request = nock(API_URL)
+        .get('/organizations/' + data.id + '/members/' + data.user_id + '/roles')
+        .reply(200);
+    });
+
+    it('should accept a callback', function(done) {
+      this.organizations.getMemberRoles(data, done.bind(null, null));
+    });
+
+    it('should return a promise when no callback is given', function(done) {
+      this.organizations.getMemberRoles(data).then(done.bind(null, null));
+    });
+
+    it('should perform a GET request to /api/v2/organizations/org_ID/members/user_id/roles', function(done) {
+      var request = this.request;
+
+      this.organizations.getMemberRoles(data).then(function() {
+        expect(request.isDone()).to.be.true;
+
+        done();
+      });
+    });
+
+    it('should pass any errors to the promise catch handler', function(done) {
+      nock.cleanAll();
+
+      var request = nock(API_URL)
+        .get('/organizations/' + data.id + '/members/' + data.user_id + '/roles')
+        .reply(500);
+
+      this.organizations.getMemberRoles(data).catch(function(err) {
+        expect(err).to.exist;
+
+        done();
+      });
+    });
+
+    it('should include the token in the authorization header', function(done) {
+      nock.cleanAll();
+
+      var request = nock(API_URL)
+        .get('/organizations/' + data.id + '/members/' + data.user_id + '/roles')
+        .matchHeader('authorization', 'Bearer ' + this.token)
+        .reply(200);
+
+      this.organizations.getMemberRoles(data).then(function() {
+        expect(request.isDone()).to.be.true;
+
+        done();
+      });
+    });
+  });
+
+  describe('#addMemberRoles', function() {
+    beforeEach(function() {
+      this.data = {
+        id: 'org_123',
+        user_id: 'user_id'
+      };
+      this.body = { roles: ['user_id'] };
+
+      this.request = nock(API_URL)
+        .post(
+          '/organizations/' + this.data.id + '/members/' + this.data.user_id + '/roles',
+          this.body
+        )
+        .reply(200);
+    });
+
+    it('should accept a callback', function(done) {
+      this.organizations.addMemberRoles(this.data, this.body, function() {
+        done();
+      });
+    });
+
+    it('should return a promise if no callback is given', function(done) {
+      this.organizations
+        .addMemberRoles(this.data, this.body)
+        .then(done.bind(null, null))
+        .catch(done.bind(null, null));
+    });
+
+    it('should pass any errors to the promise catch handler', function(done) {
+      nock.cleanAll();
+
+      var request = nock(API_URL)
+        .post('/organizations/' + this.data.id + '/members/' + this.data.user_id + '/roles')
+        .reply(500);
+
+      this.organizations.addMemberRoles(this.data, {}).catch(function(err) {
+        expect(err).to.exist;
+
+        done();
+      });
+    });
+
+    it('should perform a POST request to /api/v2/organizations/org_id/members/user_id/roles', function(done) {
+      var request = this.request;
+
+      this.organizations.addMemberRoles(this.data, this.body).then(function() {
+        expect(request.isDone()).to.be.true;
+
+        done();
+      });
+    });
+
+    it('should return error when id is not sent', function() {
+      var _this = this;
+      expect(function() {
+        _this.organizations.addMemberRoles({ id: null }, {}, function() {});
+      }).to.throw('The organization ID passed in params cannot be null or undefined');
+    });
+
+    it('should return error when id is not sent', function() {
+      var _this = this;
+      expect(function() {
+        _this.organizations.addMemberRoles({ id: 123 }, {}, function() {});
+      }).to.throw('The organization ID has to be a string');
+    });
+
+    it('should return error when id is not sent', function() {
+      var _this = this;
+      expect(function() {
+        _this.organizations.addMemberRoles({ id: 'org_123', user_id: null }, {}, function() {});
+      }).to.throw('The user ID passed in params cannot be null or undefined');
+    });
+
+    it('should return error when id is not sent', function() {
+      var _this = this;
+      expect(function() {
+        _this.organizations.addMemberRoles({ id: 'org_123', user_id: 123 }, {}, function() {});
+      }).to.throw('The user ID has to be a string');
+    });
+
+    it('should pass the data in the body of the request', function(done) {
+      nock.cleanAll();
+
+      var request = nock(API_URL)
+        .post(
+          '/organizations/' + this.data.id + '/members/' + this.data.user_id + '/roles',
+          this.body
+        )
+        .reply(200);
+
+      this.organizations.addMemberRoles(this.data, this.body).then(function() {
+        expect(request.isDone()).to.be.true;
+
+        done();
+      });
+    });
+
+    it('should include the token in the Authorization header', function(done) {
+      nock.cleanAll();
+
+      var request = nock(API_URL)
+        .post('/organizations/' + this.data.id + '/members/' + this.data.user_id + '/roles')
+        .matchHeader('Authorization', 'Bearer ' + this.token)
+        .reply(200);
+
+      this.organizations.addMemberRoles(this.data, {}).then(function() {
+        expect(request.isDone()).to.be.true;
+
+        done();
+      });
+    });
+  });
+
+  describe('#removeMemberRoles', function() {
+    beforeEach(function() {
+      this.data = {
+        id: 'org_123',
+        user_id: 'user_123'
+      };
+
+      this.body = { roles: ['user_id'] };
+
+      this.request = nock(API_URL)
+        .delete('/organizations/' + this.data.id + '/members/' + this.data.user_id + '/roles', {})
+        .reply(200);
+    });
+
+    it('should validate empty organizationId', function() {
+      var _this = this;
+      expect(function() {
+        _this.organizations.removeMemberRoles({ id: null }, this.body, function() {});
+      }).to.throw('The organization ID passed in params cannot be null or undefined');
+    });
+
+    it('should validate non-string organizationId', function() {
+      var _this = this;
+      expect(function() {
+        _this.organizations.removeMemberRoles({ id: 123 }, _this.body, function() {});
+      }).to.throw('The organization ID has to be a string');
+    });
+
+    it('should return a promise if no callback is given', function(done) {
+      this.organizations
+        .removeMemberRoles(this.data, this.body)
+        .then(done.bind(null, null))
+        .catch(done.bind(null, null));
+    });
+
+    it('should pass any errors to the promise catch handler', function(done) {
+      nock.cleanAll();
+
+      var request = nock(API_URL)
+        .delete('/organizations/' + this.data.id + '/members/' + this.data.user_id + '/roles')
+        .reply(500);
+
+      this.organizations.removeMemberRoles(this.data, this.body).catch(function(err) {
+        expect(err).to.exist;
+
+        done();
+      });
+    });
+
+    it('should return error when id is not sent', function() {
+      var _this = this;
+      expect(function() {
+        _this.organizations.removeMemberRoles({ id: 'org_123', user_id: null }, {}, function() {});
+      }).to.throw('The user ID passed in params cannot be null or undefined');
+    });
+
+    it('should return error when id is not sent', function() {
+      var _this = this;
+      expect(function() {
+        _this.organizations.removeMemberRoles({ id: 'org_123', user_id: 123 }, {}, function() {});
+      }).to.throw('The user ID has to be a string');
+    });
+
+    it('should perform a DELETE request to /api/v2/organizations/organization_id/members/user_id/roles', function(done) {
+      var request = this.request;
+
+      var request = nock(API_URL)
+        .delete(
+          '/organizations/' + this.data.id + '/members/' + this.data.user_id + '/roles',
+          this.body
+        )
+        .reply(200);
+
+      this.organizations.removeMemberRoles(this.data, this.body, function() {
+        expect(request.isDone()).to.be.true;
+
+        done();
+      });
+    });
+
+    it('should include the token in the Authorization header', function(done) {
+      nock.cleanAll();
+
+      var request = nock(API_URL)
+        .delete(
+          '/organizations/' + this.data.id + '/members/' + this.data.user_id + '/roles',
+          this.body
+        )
+        .matchHeader('Authorization', 'Bearer ' + this.token)
+        .reply(200);
+
+      this.organizations.removeMemberRoles(this.data, this.body).then(function() {
+        expect(request.isDone()).to.be.true;
+
+        done();
+      });
+    });
+  });
+
+  //// Invites
+  describe('#getInvitations', function() {
+    var data = {
+      id: 'org_id'
+    };
+
+    beforeEach(function() {
+      this.request = nock(API_URL)
+        .get('/organizations/' + data.id + '/invitations')
+        .reply(200);
+    });
+
+    it('should accept a callback', function(done) {
+      this.organizations.getInvitations(data, done.bind(null, null));
+    });
+
+    it('should return a promise when no callback is given', function(done) {
+      this.organizations.getInvitations(data).then(done.bind(null, null));
+    });
+
+    it('should perform a GET request to /api/v2/organizations/org_ID/invitations', function(done) {
+      var request = this.request;
+
+      this.organizations.getInvitations(data).then(function() {
+        expect(request.isDone()).to.be.true;
+
+        done();
+      });
+    });
+
+    it('should pass any errors to the promise catch handler', function(done) {
+      nock.cleanAll();
+
+      var request = nock(API_URL)
+        .get('/organizations/' + data.id + '/invitations')
+        .reply(500);
+
+      this.organizations.getInvitations(data).catch(function(err) {
+        expect(err).to.exist;
+
+        done();
+      });
+    });
+
+    it('should include the token in the authorization header', function(done) {
+      nock.cleanAll();
+
+      var request = nock(API_URL)
+        .get('/organizations/' + data.id + '/invitations')
+        .matchHeader('authorization', 'Bearer ' + this.token)
+        .reply(200);
+
+      this.organizations.getInvitations(data).then(function() {
+        expect(request.isDone()).to.be.true;
+
+        done();
+      });
+    });
+  });
+
+  describe('#getInvitation', function() {
+    var data = {
+      id: 'org_id',
+      invitation_id: 'inv_123'
+    };
+
+    beforeEach(function() {
+      this.request = nock(API_URL)
+        .get('/organizations/' + data.id + '/invitations/' + data.invitation_id)
+        .reply(200);
+    });
+
+    it('should accept a callback', function(done) {
+      this.organizations.getInvitation(data, done.bind(null, null));
+    });
+
+    it('should return a promise when no callback is given', function(done) {
+      this.organizations.getInvitation(data).then(done.bind(null, null));
+    });
+
+    it('should perform a GET request to /api/v2/organizations/rol_ID/invitations/inv_id', function(done) {
+      var request = this.request;
+
+      this.organizations.getInvitation(data).then(function() {
+        expect(request.isDone()).to.be.true;
+
+        done();
+      });
+    });
+
+    it('should pass any errors to the promise catch handler', function(done) {
+      nock.cleanAll();
+
+      var request = nock(API_URL)
+        .get('/organizations/' + data.id + '/invitations/' + data.invitation_id)
+        .reply(500);
+
+      this.organizations.getInvitation(data).catch(function(err) {
+        expect(err).to.exist;
+
+        done();
+      });
+    });
+
+    it('should return error when id is not sent', function() {
+      var _this = this;
+      expect(function() {
+        _this.organizations.getInvitation({ id: null }, function() {});
+      }).to.throw('The organization ID passed in params cannot be null or undefined');
+    });
+
+    it('should return error when id is not sent', function() {
+      var _this = this;
+      expect(function() {
+        _this.organizations.getInvitation({ id: 123 }, function() {});
+      }).to.throw('The organization ID has to be a string');
+    });
+
+    it('should return error when id is not sent', function() {
+      var _this = this;
+      expect(function() {
+        _this.organizations.getInvitation({ id: 'org_123', invitation_id: null }, function() {});
+      }).to.throw('The invitation ID passed in params cannot be null or undefined');
+    });
+
+    it('should return error when id is not sent', function() {
+      var _this = this;
+      expect(function() {
+        _this.organizations.getInvitation({ id: 'org_123', invitation_id: 123 }, function() {});
+      }).to.throw('The invitation ID has to be a string');
+    });
+
+    it('should include the token in the authorization header', function(done) {
+      nock.cleanAll();
+
+      var request = nock(API_URL)
+        .get('/organizations/' + data.id + '/invitations/' + data.invitation_id)
+        .matchHeader('authorization', 'Bearer ' + this.token)
+        .reply(200);
+
+      this.organizations.getInvitation(data).then(function() {
+        expect(request.isDone()).to.be.true;
+
+        done();
+      });
+    });
+  });
+
+  describe('#createInvitation', function() {
+    beforeEach(function() {
+      this.data = {
+        id: 'org_123'
+      };
+      this.body = {
+        invitee: 'inv',
+        client_id: 'cid'
+      };
+
+      this.request = nock(API_URL)
+        .post('/organizations/' + this.data.id + '/invitations', {})
+        .reply(200);
+    });
+
+    it('should accept a callback', function(done) {
+      this.organizations.createInvitation(this.data, {}, function() {
+        done();
+      });
+    });
+
+    it('should return a promise if no callback is given', function(done) {
+      this.organizations
+        .createInvitation(this.data, {})
+        .then(done.bind(null, null))
+        .catch(done.bind(null, null));
+    });
+
+    it('should pass any errors to the promise catch handler', function(done) {
+      nock.cleanAll();
+
+      var request = nock(API_URL)
+        .post('/organizations/' + this.data.id + '/invitations')
+        .reply(500);
+
+      this.organizations.createInvitation(this.data, {}).catch(function(err) {
+        expect(err).to.exist;
+
+        done();
+      });
+    });
+
+    it('should perform a POST request to /api/v2/organizations/org_id/invitations', function(done) {
+      var request = this.request;
+
+      this.organizations.createInvitation(this.data, {}).then(function() {
+        expect(request.isDone()).to.be.true;
+
+        done();
+      });
+    });
+
+    it('should return error when id is not sent', function() {
+      var _this = this;
+      expect(function() {
+        _this.organizations.createInvitation({ id: null }, {}, function() {});
+      }).to.throw('The organization ID passed in params cannot be null or undefined');
+    });
+
+    it('should return error when id is not sent', function() {
+      var _this = this;
+      expect(function() {
+        _this.organizations.createInvitation({ id: 123 }, {}, function() {});
+      }).to.throw('The organization ID has to be a string');
+    });
+
+    it('should pass the data in the body of the request', function(done) {
+      nock.cleanAll();
+
+      var request = nock(API_URL)
+        .post('/organizations/' + this.data.id + '/invitations', this.body)
+        .reply(200);
+
+      this.organizations.createInvitation(this.data, this.body).then(function() {
+        expect(request.isDone()).to.be.true;
+
+        done();
+      });
+    });
+
+    it('should include the token in the Authorization header', function(done) {
+      nock.cleanAll();
+
+      var request = nock(API_URL)
+        .post('/organizations/' + this.data.id + '/invitations')
+        .matchHeader('Authorization', 'Bearer ' + this.token)
+        .reply(200);
+
+      this.organizations.createInvitation(this.data, {}).then(function() {
+        expect(request.isDone()).to.be.true;
+
+        done();
+      });
+    });
+  });
+
+  describe('#deleteInvitation', function() {
+    beforeEach(function() {
+      this.data = {
+        id: 'org_123',
+        invitation_id: 'inv_123'
+      };
+
+      this.request = nock(API_URL)
+        .delete('/organizations/' + this.data.id + '/invitations/' + this.data.invitation_id, {})
+        .reply(200);
+    });
+
+    it('should validate empty organizationId', function() {
+      var _this = this;
+      expect(function() {
+        _this.organizations.deleteInvitation({ id: null }, function() {});
+      }).to.throw('The organization ID passed in params cannot be null or undefined');
+    });
+
+    it('should validate non-string organizationId', function() {
+      var _this = this;
+      expect(function() {
+        _this.organizations.deleteInvitation({ id: 123 }, function() {});
+      }).to.throw('The organization ID has to be a string');
+    });
+
+    it('should return a promise if no callback is given', function(done) {
+      this.organizations
+        .removeMembers(this.data)
+        .then(done.bind(null, null))
+        .catch(done.bind(null, null));
+    });
+
+    it('should pass any errors to the promise catch handler', function(done) {
+      nock.cleanAll();
+
+      var request = nock(API_URL)
+        .delete('/organizations/' + this.data.id + '/invitations/' + this.data.invitation_id, {})
+        .reply(500);
+
+      this.organizations.deleteInvitation(this.data).catch(function(err) {
+        expect(err).to.exist;
+
+        done();
+      });
+    });
+
+    it('should perform a DELETE request to /api/v2/organizations/organization_id/invitations/inv_id', function(done) {
+      nock.cleanAll();
+
+      var request = nock(API_URL)
+        .delete('/organizations/' + this.data.id + '/invitations/' + this.data.invitation_id, {})
+        .reply(200);
+
+      this.organizations.deleteInvitation(this.data, function(err) {
+        expect(request.isDone()).to.be.true;
+
+        done();
+      });
+    });
+
+    it('should return error when id is not sent', function() {
+      var _this = this;
+      expect(function() {
+        _this.organizations.deleteInvitation({ id: 'org_123', invitation_id: null }, function() {});
+      }).to.throw('The invitation ID passed in params cannot be null or undefined');
+    });
+
+    it('should return error when id is not sent', function() {
+      var _this = this;
+      expect(function() {
+        _this.organizations.deleteInvitation({ id: 'org_123', invitation_id: 123 }, function() {});
+      }).to.throw('The invitation ID has to be a string');
+    });
+
+    it('should include the token in the Authorization header', function(done) {
+      nock.cleanAll();
+
+      var request = nock(API_URL)
+        .delete('/organizations/' + this.data.id + '/invitations/' + this.data.invitation_id, {})
+        .matchHeader('Authorization', 'Bearer ' + this.token)
+        .reply(200);
+
+      this.organizations.deleteInvitation(this.data).then(function() {
+        expect(request.isDone()).to.be.true;
+
+        done();
+      });
+    });
+  });
+});
diff --git a/test/management/users.tests.js b/test/management/users.tests.js
index 4c3d2b94d..32613b97c 100644
--- a/test/management/users.tests.js
+++ b/test/management/users.tests.js
@@ -38,7 +38,8 @@ describe('UsersManager', function() {
       'removeRoles',
       'getPermissions',
       'assignPermissions',
-      'removePermissions'
+      'removePermissions',
+      'getUserOrganizations'
     ];
 
     methods.forEach(function(method) {
@@ -1627,4 +1628,63 @@ describe('UsersManager', function() {
       });
     });
   });
+
+  describe('#getUserOrganizations', function() {
+    var data = {
+      id: 'user_id'
+    };
+
+    beforeEach(function() {
+      this.request = nock(API_URL)
+        .get('/users/' + data.id + '/organizations')
+        .reply(200);
+    });
+
+    it('should accept a callback', function(done) {
+      this.users.getUserOrganizations(data, done.bind(null, null));
+    });
+
+    it('should return a promise when no callback is given', function(done) {
+      this.users.getUserOrganizations(data).then(done.bind(null, null));
+    });
+
+    it('should perform a GET request to /api/v2/users/user_id/organizations', function(done) {
+      var request = this.request;
+
+      this.users.getUserOrganizations(data).then(function() {
+        expect(request.isDone()).to.be.true;
+
+        done();
+      });
+    });
+
+    it('should pass any errors to the promise catch handler', function(done) {
+      nock.cleanAll();
+
+      var request = nock(API_URL)
+        .get('/users/' + data.id + '/organizations')
+        .reply(500);
+
+      this.users.getUserOrganizations(data).catch(function(err) {
+        expect(err).to.exist;
+
+        done();
+      });
+    });
+
+    it('should include the token in the authorization header', function(done) {
+      nock.cleanAll();
+
+      var request = nock(API_URL)
+        .get('/users/' + data.id + '/organizations')
+        .matchHeader('authorization', 'Bearer ' + this.token)
+        .reply(200);
+
+      this.users.getUserOrganizations(data).then(function() {
+        expect(request.isDone()).to.be.true;
+
+        done();
+      });
+    });
+  });
 });