Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 19 additions & 17 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,26 +107,28 @@ async function authorize(options) {
return fetch(`${ims}/ims/exchange/jwt/`, postOptions)
.catch(e => throwRequestFailedError(e.message))
.then(res => {
if (res.ok) {
return res.json();
} else {
throwRequestFailedError(res.statusText);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

delete the throwRequestFailedError here and let the details emerge near lines 123-130

}
return res.json().then(data => {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's desirable to let res.json throw if there's something wrong, This gives us a stack trace and insight that there was something wrong doing the exchange. In this scenario, we would already have made the roundtrip, so let's figure out why it blew up.

return {
ok: res.ok,
json: data
};
});
})
.then(json => {
.then(({ ok, json }) => {
const { access_token, error, error_description } = json;
if (!access_token) {
if (error && error_description) {
const swapError = new Error(error_description);
swapError.code = error;
throw swapError;
} else {
throwUnexpectedResponseError(
`The response body is as follows: ${JSON.stringify(json)}`
);
}
if (ok && access_token) {
return json;
}

if (error && error_description) {
const swapError = new Error(error_description);
swapError.code = error;
throw swapError;
} else {
throwUnexpectedResponseError(
`The response body is as follows: ${JSON.stringify(json)}`
);
}
return json;
});
}

Expand Down
69 changes: 36 additions & 33 deletions test/auth.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,15 @@ let mockResultSuccess = Promise.resolve({
Promise.resolve({ access_token: mockAccessToken, expires_in: 123456 })
});
// attempting to contact the API threw an error
let mockEndpointFailure = Promise.reject(new Error('Endpoint error.'));
// simple API failure
let mockEndpointFailure = Promise.reject(new Error('500 error from server.'));
// simple API failure, likely a customer issue
let mockResultFailure = Promise.resolve({
ok: false,
status: 400,
statusText: 'You did something wrong for the jwt exchange.',
json: () =>
Promise.resolve({
error: 'my_error_code',
error_description: 'This is the error description.'
error_description: 'This is the error description. Customer issue.'
})
});
// no access token, error, or error_description
Expand All @@ -42,6 +41,7 @@ let mockResultFailureMalformedServerResponse = Promise.resolve({
status: 200,
json: () => Promise.resolve({ foo: 'bar', baz: 'faz' })
});
// good API call, but got an error with no access token
let mockResultFailureNoJWT = Promise.resolve({
ok: true,
status: 200,
Expand Down Expand Up @@ -233,24 +233,27 @@ describe('Fetch jwt', () => {
).resolves.toEqual({ access_token: mockAccessToken, expires_in: 123456 });
});

test('endpoint error thrown, unkown reason', () => {
expect.assertions(1);
test('endpoint error thrown, unknown reason', async () => {
expect.assertions(2);
fetch.mockImplementation(() => mockEndpointFailure);
return expect(
auth({
try {
await auth({
clientId,
clientSecret,
technicalAccountId,
orgId,
metaScopes,
privateKey
})
).rejects.toThrow(
'Request failed while swapping the jwt token. Endpoint error.'
);
});
} catch (e) {
expect(e.message).toBe(
'Request failed while swapping the jwt token. 500 error from server.'
);
expect(e.code).toBe('request_failed');
}
});

test('invalid jwt, expected endpoint error', () => {
test('invalid jwt, expected endpoint error', async () => {
expect.assertions(1);
fetch.mockImplementation(() => mockResultFailure);
return expect(
Expand All @@ -262,44 +265,44 @@ describe('Fetch jwt', () => {
metaScopes,
privateKey
})
).rejects.toThrow(
'Request failed while swapping the jwt token. You did something wrong for the jwt exchange.'
);
).rejects.toThrow('This is the error description. Customer issue.');
});

test('malformed server response, dump entire json() call', () => {
expect.assertions(1);
test('malformed server response, dump entire json() call', async () => {
expect.assertions(2);
fetch.mockImplementation(() => mockResultFailureMalformedServerResponse);
return expect(
auth({
try {
await auth({
clientId,
clientSecret,
technicalAccountId,
orgId,
metaScopes,
privateKey
})
).rejects.toThrow(
new Error(
});
} catch (e) {
expect(e.message).toBe(
'Unexpected response received while swapping the jwt token. The response body is as follows: {"foo":"bar","baz":"faz"}'
)
);
);
expect(e.code).toBe('invalid_response_body');
}
});

test('no access token, valid server response', () => {
expect.assertions(1);
test('no access token returned from IMS, valid server response', async () => {
expect.assertions(2);
fetch.mockImplementation(() => mockResultFailureNoJWT);
return expect(
auth({
try {
await auth({
clientId,
clientSecret,
technicalAccountId,
orgId,
metaScopes,
privateKey
})
).rejects.toThrow(
new Error('This is the error description. No JWT present.')
);
});
} catch (e) {
expect(e.message).toBe('This is the error description. No JWT present.');
expect(e.code).toBe('my_error_code_no_jwt');
}
});
});