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
16 changes: 16 additions & 0 deletions packages/javascript/src/errors/__tests__/ThunderIDAPIError.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -177,4 +177,20 @@ describe('ThunderIDAPIError — structured response body parsing', (): void => {
const error: ThunderIDAPIError = new ThunderIDAPIError(errorText, 'CODE', 'javascript', 401);
expect(error.message).toBe('Invalid credentials provided');
});

it('should never surface a raw expired-flow response body to consumers', (): void => {
const errorText: string = JSON.stringify({
code: 'FES-1004',
description: {
defaultValue: 'Invalid flow execution ID provided in the request',
key: 'error.flowexecservice.invalid_execution_id_description',
},
message: {defaultValue: 'Invalid request', key: 'error.flowexecservice.invalid_execution_id'},
});
const error: ThunderIDAPIError = new ThunderIDAPIError(errorText, 'FES-1004', 'react', 400, 'Bad Request');

expect(error.message).not.toContain('FES-1004');
expect(error.message).not.toContain('error.flowexecservice');
expect(error.code).toBe('FES-1004');
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
* under the License.
*/

import {ThunderIDAPIError} from '@thunderid/browser';
import {FC, ReactElement, ReactNode, useMemo} from 'react';
import BaseAcceptInvite, {BaseAcceptInviteRenderProps, AcceptInviteFlowResponse} from './BaseAcceptInvite';

Expand Down Expand Up @@ -189,7 +190,7 @@ const AcceptInvite: FC<AcceptInviteProps> = ({
* Makes an unauthenticated request to /flow/execute endpoint.
*/
const handleSubmit = async (payload: Record<string, any>): Promise<AcceptInviteFlowResponse> => {
const response: any = await fetch(`${apiBaseUrl}/flow/execute`, {
const response: Response = await fetch(`${apiBaseUrl}/flow/execute`, {
body: JSON.stringify({
...payload,
verbose: true,
Expand All @@ -202,8 +203,15 @@ const AcceptInvite: FC<AcceptInviteProps> = ({
});

if (!response.ok) {
const errorText: any = await response.text();
throw new Error(`Request failed: ${errorText}`);
const errorText: string = await response.text();
// ThunderIDAPIError resolves the raw API body into a readable message instead of leaking it.
throw new ThunderIDAPIError(
errorText,
'AcceptInvite-ResponseError-001',
'react',
response.status,
response.statusText,
);
}

return response.json();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
* under the License.
*/

import {ThunderIDAPIError} from '@thunderid/browser';
import {type Component, type PropType, type SetupContext, type VNode, defineComponent, h} from 'vue';
import BaseAcceptInvite from './BaseAcceptInvite';
import type {AcceptInviteFlowResponse, BaseAcceptInviteRenderProps} from './BaseAcceptInvite';
Expand Down Expand Up @@ -78,7 +79,14 @@ const AcceptInvite: Component = defineComponent({

if (!response.ok) {
const errorText: string = await response.text();
throw new Error(`Request failed: ${errorText}`);
// ThunderIDAPIError resolves the raw API body into a readable message instead of leaking it.
throw new ThunderIDAPIError(
errorText,
'AcceptInvite-ResponseError-001',
'vue',
response.status,
response.statusText,
);
}

return response.json();
Expand Down
Loading