Skip to content

Commit af7ffe7

Browse files
fix(ui): add fallback to interaction required error in MsalAuthenticator (#27189)
* fix(ui): add fallback to interaction required error * fix(ui): update MsalAuthenticator test to validate popup-fallback path Agent-Logs-Url: https://github.com/open-metadata/OpenMetadata/sessions/b430d4e3-eead-4b95-9b4e-0b6775ca20e6 Co-authored-by: chirag-madlani <12962843+chirag-madlani@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
1 parent 4572961 commit af7ffe7

File tree

2 files changed

+42
-3
lines changed

2 files changed

+42
-3
lines changed

openmetadata-ui/src/main/resources/ui/src/components/Auth/AppAuthenticators/MsalAuthenticator.test.tsx

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,18 @@ jest.mock('../../../utils/AuthProvider.util', () => ({
3636
})),
3737
}));
3838

39+
jest.mock('../../../utils/ToastUtils', () => ({
40+
showErrorToast: jest.fn(),
41+
}));
42+
43+
jest.mock('../../../utils/CommonUtils', () => ({
44+
Transi18next: jest.fn(() => null),
45+
}));
46+
47+
jest.mock('../../../utils/BrowserUtils', () => ({
48+
getPopupSettingLink: jest.fn(() => 'https://example.com/popup-settings'),
49+
}));
50+
3951
const mockInstance = {
4052
loginPopup: jest.fn(),
4153
loginRedirect: jest.fn(),
@@ -162,11 +174,37 @@ describe('MsalAuthenticator', () => {
162174
expect(result).toBe('mock-id-token');
163175
});
164176

165-
it('should throw InteractionRequiredAuthError when renewIdToken encounters expired session', async () => {
177+
it('should fall back to loginPopup when renewIdToken encounters InteractionRequiredAuthError', async () => {
178+
const interactionError = new InteractionRequiredAuthError(
179+
'interaction_required'
180+
);
181+
mockInstance.acquireTokenSilent.mockRejectedValueOnce(interactionError);
182+
mockInstance.loginPopup.mockResolvedValueOnce({
183+
account: { username: 'test@example.com' },
184+
idToken: 'popup-token',
185+
});
186+
187+
render(
188+
<MsalAuthenticator
189+
{...mockProps}
190+
ref={(ref) => (authenticatorRef = ref)}
191+
/>
192+
);
193+
194+
const result = await authenticatorRef?.renewIdToken();
195+
196+
expect(mockInstance.acquireTokenSilent).toHaveBeenCalled();
197+
expect(mockInstance.loginPopup).toHaveBeenCalled();
198+
expect(result).toBe('mock-id-token');
199+
});
200+
201+
it('should throw when renewIdToken popup fallback also fails', async () => {
166202
const interactionError = new InteractionRequiredAuthError(
167203
'interaction_required'
168204
);
205+
const popupError = new Error('popup_window_error');
169206
mockInstance.acquireTokenSilent.mockRejectedValueOnce(interactionError);
207+
mockInstance.loginPopup.mockRejectedValueOnce(popupError);
170208

171209
render(
172210
<MsalAuthenticator
@@ -176,9 +214,10 @@ describe('MsalAuthenticator', () => {
176214
);
177215

178216
await expect(authenticatorRef?.renewIdToken()).rejects.toThrow(
179-
InteractionRequiredAuthError
217+
'popup_window_error'
180218
);
181219
expect(mockInstance.acquireTokenSilent).toHaveBeenCalled();
220+
expect(mockInstance.loginPopup).toHaveBeenCalled();
182221
});
183222

184223
it('should show loader when interaction is in progress', () => {

openmetadata-ui/src/main/resources/ui/src/components/Auth/AppAuthenticators/MsalAuthenticator.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ const MsalAuthenticator = forwardRef<AuthenticatorRef, Props>(
133133
};
134134

135135
const renewIdToken = async () => {
136-
const user = await fetchIdToken();
136+
const user = await fetchIdToken(true);
137137

138138
return user.id_token;
139139
};

0 commit comments

Comments
 (0)