Repository: auth0/node-auth0 (ts)

Issue:
Callback may be invoke more than once when handling errors
### Describe the problem

When the new `includeResponseHeaders` is enabled, and a callback is passed to the client and an error occurs, the callback will be invoked twice. In addition, if the callback doesn't return a truthy value, it could be invoked a third time.

### What was the expected behavior?

The callback should only be invoked once.

### Reproduction

Here is a failing test case:
```js
  it('should accept a callback and handle errors with response headers', (done) => {
    const providerMock = {
      async getAccessToken() {
        return 'fake-token';
      },
    };

    const errorBody = { error: 'message' };
    nock(API_URL).get('/some-resource').reply(500, errorBody);

    const options = {
      headers: {},
      includeResponseHeaders: true,
    };
    const client = new Auth0RestClient(`${API_URL}/some-resource`, options, providerMock);
    client.getAll((err) => {
      expect(err).to.not.null;
      expect(err.message).to.be.equal(JSON.stringify(errorBody));
      done();
      nock.cleanAll();
    });
  });
```

### Environment

- **Version of this library used:** latest [master](https://github.com/auth0/node-auth0/commit/7c3e31a25fd282828af6fbc75c2e66a70b5f1ebc)
- **Which framework are you using, if applicable:** n/a
- **Other modules/plugins/libraries that might be involved:** n/a
- **Any other relevant information you think would be useful:** n/a


Pull request:
Prevent calling the callback more than once
### Changes

During the login in `Auth0RestClient._request`:

* If the callback is passed, do not call resolve or reject as calling reject will invoke the callback again
* if there is an error, return after handling the error instead of invoking the callback again

### References

Fixes #758 

### 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

- [x] I have read the [Auth0 general contribution guidelines](https://github.com/auth0/open-source-template/blob/master/GENERAL-CONTRIBUTING.md)
- [x] I have read the [Auth0 Code of Conduct](https://github.com/auth0/open-source-template/blob/master/CODE-OF-CONDUCT.md)
- [x] All existing and new tests complete without errors


Patch:
diff --git a/src/Auth0RestClient.js b/src/Auth0RestClient.js
index 92080714b..88ff32958 100644
--- a/src/Auth0RestClient.js
+++ b/src/Auth0RestClient.js
@@ -73,9 +73,12 @@ class Auth0RestClient {
       this.restClient[method](...args, (err, data, headers) => {
         const payload = { data, headers };
         if (err) {
-          (callback && callback(err)) || reject(err);
+          if (callback) callback(err);
+          else reject(err);
+          return;
         }
-        (callback && callback(null, payload)) || resolve(payload);
+        if (callback) callback(null, payload);
+        else resolve(payload);
       });
     });
   }


Test patch:
diff --git a/test/auth0-rest-client.tests.js b/test/auth0-rest-client.tests.js
index a0a3ef38a..96aed2b01 100644
--- a/test/auth0-rest-client.tests.js
+++ b/test/auth0-rest-client.tests.js
@@ -186,6 +186,29 @@ describe('Auth0RestClient', () => {
     });
   });
 
+  it('should accept a callback and handle errors with response headers', (done) => {
+    const providerMock = {
+      async getAccessToken() {
+        return 'fake-token';
+      },
+    };
+
+    const errorBody = { error: 'message' };
+    nock(API_URL).get('/some-resource').reply(500, errorBody);
+
+    const options = {
+      headers: {},
+      includeResponseHeaders: true,
+    };
+    const client = new Auth0RestClient(`${API_URL}/some-resource`, options, providerMock);
+    client.getAll((err) => {
+      expect(err).to.not.null;
+      expect(err.message).to.be.equal(JSON.stringify(errorBody));
+      done();
+      nock.cleanAll();
+    });
+  });
+
   it('should set access token as Authorization header in options object', async function () {
     nock(API_URL).get('/some-resource').reply(200);