Skip to content

Commit 07f1a0d

Browse files
chore(ui): Replace ssoSilent with acquireTokenSilent for token renewal (#27116)
* chore(ui): Replace ssoSilent with acquireTokenSilent for token renewal * fix(ui): update MsalAuthenticator tests to use acquireTokenSilent Agent-Logs-Url: https://github.com/open-metadata/OpenMetadata/sessions/4944b541-e32a-4904-9ac9-d1dc62acb565 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> (cherry picked from commit 65effdb)
1 parent 5d85672 commit 07f1a0d

3 files changed

Lines changed: 32 additions & 12 deletions

File tree

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

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,10 @@
1010
* See the License for the specific language governing permissions and
1111
* limitations under the License.
1212
*/
13-
import { InteractionStatus } from '@azure/msal-browser';
13+
import {
14+
InteractionRequiredAuthError,
15+
InteractionStatus,
16+
} from '@azure/msal-browser';
1417
import { useMsal } from '@azure/msal-react';
1518
import { act, render, screen } from '@testing-library/react';
1619
import { msalLoginRequest } from '../../../utils/AuthProvider.util';
@@ -37,7 +40,7 @@ const mockInstance = {
3740
loginPopup: jest.fn(),
3841
loginRedirect: jest.fn(),
3942
handleRedirectPromise: jest.fn(),
40-
ssoSilent: jest.fn(),
43+
acquireTokenSilent: jest.fn(),
4144
logout: jest.fn(),
4245
};
4346

@@ -141,7 +144,7 @@ describe('MsalAuthenticator', () => {
141144
});
142145

143146
it('should handle renewIdToken successfully', async () => {
144-
mockInstance.ssoSilent.mockResolvedValueOnce({
147+
mockInstance.acquireTokenSilent.mockResolvedValueOnce({
145148
account: { username: 'test@example.com' },
146149
idToken: 'new-token',
147150
});
@@ -155,10 +158,29 @@ describe('MsalAuthenticator', () => {
155158

156159
const result = await authenticatorRef?.renewIdToken();
157160

158-
expect(mockInstance.ssoSilent).toHaveBeenCalled();
161+
expect(mockInstance.acquireTokenSilent).toHaveBeenCalled();
159162
expect(result).toBe('mock-id-token');
160163
});
161164

165+
it('should throw InteractionRequiredAuthError when renewIdToken encounters expired session', async () => {
166+
const interactionError = new InteractionRequiredAuthError(
167+
'interaction_required'
168+
);
169+
mockInstance.acquireTokenSilent.mockRejectedValueOnce(interactionError);
170+
171+
render(
172+
<MsalAuthenticator
173+
{...mockProps}
174+
ref={(ref) => (authenticatorRef = ref)}
175+
/>
176+
);
177+
178+
await expect(authenticatorRef?.renewIdToken()).rejects.toThrow(
179+
InteractionRequiredAuthError
180+
);
181+
expect(mockInstance.acquireTokenSilent).toHaveBeenCalled();
182+
});
183+
162184
it('should show loader when interaction is in progress', () => {
163185
(useMsal as jest.Mock).mockReturnValue({
164186
instance: mockInstance,

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ const MsalAuthenticator = forwardRef<AuthenticatorRef, Props>(
8787
scopes: msalLoginRequest.scopes,
8888
};
8989
try {
90-
const response = await instance.ssoSilent(tokenRequest);
90+
const response = await instance.acquireTokenSilent(tokenRequest);
9191
const msalResponse = await parseMSALResponse(response);
9292

9393
return msalResponse;
@@ -107,6 +107,7 @@ const MsalAuthenticator = forwardRef<AuthenticatorRef, Props>(
107107
i18nKey="message.popup-block-message"
108108
renderElement={
109109
<a
110+
aria-label="Open popup settings"
110111
href={getPopupSettingLink()}
111112
rel="noopener noreferrer"
112113
target="_blank"

openmetadata-ui/src/main/resources/ui/src/utils/Auth/TokenService/TokenServiceUtil.ts

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,12 @@ class TokenService {
3737

3838
// Setup Service Worker listener for token updates (if available)
3939
private setupServiceWorkerListener() {
40-
if ('serviceWorker' in navigator && 'indexedDB' in window) {
40+
if ('serviceWorker' in navigator && 'indexedDB' in globalThis) {
4141
try {
4242
navigator.serviceWorker.addEventListener('message', (event) => {
4343
if (event.data.type === 'TOKEN_UPDATE') {
4444
// Token was updated via Service Worker, notify other tabs
45-
this.refreshSuccessCallback && this.refreshSuccessCallback();
45+
this.refreshSuccessCallback?.();
4646
} else if (event.data.type === 'TOKEN_CLEARED') {
4747
// Tokens were cleared (logout), don't trigger refresh callbacks
4848
// This prevents token restoration after logout
@@ -68,7 +68,7 @@ class TokenService {
6868
}
6969

7070
public updateRefreshSuccessCallback(callback: () => void) {
71-
window.addEventListener('storage', (event) => {
71+
globalThis.addEventListener('storage', (event) => {
7272
if (event.key === REFRESHED_KEY && event.newValue === 'true') {
7373
callback(); // Notify the tab that the token was refreshed
7474
// Clear once notified
@@ -79,9 +79,6 @@ class TokenService {
7979

8080
// Refresh the token if it is expired
8181
async refreshToken() {
82-
// eslint-disable-next-line no-console
83-
console.timeLog('refreshToken', 'Token initiated refresh');
84-
8582
if (this.isTokenUpdateInProgress()) {
8683
return;
8784
}
@@ -100,7 +97,7 @@ class TokenService {
10097
if (newToken) {
10198
// Wait briefly for token to be persisted in SW+IndexedDB before notifying
10299
await new Promise((resolve) => setTimeout(resolve, 100));
103-
this.refreshSuccessCallback && this.refreshSuccessCallback();
100+
this.refreshSuccessCallback?.();
104101
// To update all the tabs on updating channel token
105102
// Notify all tabs that the token has been refreshed
106103
localStorage.setItem(REFRESHED_KEY, 'true');

0 commit comments

Comments
 (0)