msalConfig.ts
1 // Copyright (c) 2026 VPL Solutions. All rights reserved. 2 // Licensed under the MIT License. See LICENSE for details. 3 4 import { PublicClientApplication, type Configuration, LogLevel } from '@azure/msal-browser'; 5 import { config } from '../config'; 6 7 const msalConfig: Configuration = { 8 auth: { 9 clientId: config.azure.clientId, 10 authority: config.azure.tenantId 11 ? `https://login.microsoftonline.com/${config.azure.tenantId}` 12 : 'https://login.microsoftonline.com/common', 13 redirectUri: config.azure.redirectUri, 14 postLogoutRedirectUri: config.azure.redirectUri, 15 }, 16 cache: { 17 cacheLocation: 'localStorage', 18 }, 19 system: { 20 loggerOptions: { 21 logLevel: LogLevel.Verbose, 22 loggerCallback: (_level, message, containsPii) => { 23 if (containsPii) return; 24 console.log(`[MSAL] ${message}`); 25 }, 26 }, 27 }, 28 }; 29 30 // Always include openid/profile/email so idToken is present in acquireTokenSilent 31 // responses. Without openid, MSAL omits idToken from the response and 32 // response.idToken is null — causing Bearer null on all API calls. 33 export const loginRequest = { 34 scopes: config.azure.apiScope 35 ? [config.azure.apiScope, 'openid', 'profile', 'email'] 36 : ['openid', 'profile', 'email'], 37 }; 38 39 // Singleton — only instantiated when auth is enabled 40 let msalInstance: PublicClientApplication | null = null; 41 42 export function getMsalInstance(): PublicClientApplication { 43 if (!msalInstance) { 44 msalInstance = new PublicClientApplication(msalConfig); 45 } 46 return msalInstance; 47 }