@chemmangat/msal-next 3.1.1 → 3.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,97 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
+ ## [3.1.5] - 2026-03-05
6
+
7
+ ### ✨ New Feature - Separate Popup Redirect URI
8
+
9
+ **Added `popupRedirectUri` prop** - Now you can have different redirect URIs for popup vs redirect flows!
10
+
11
+ **Changes:**
12
+ - Added `popupRedirectUri` prop to MSALProvider (defaults to `/blank.html`)
13
+ - `redirectUri` prop is now used only for redirect flow
14
+ - Popup authentication automatically uses `popupRedirectUri`
15
+ - Exported `getPopupRedirectUri()` utility function
16
+
17
+ **Usage:**
18
+ ```tsx
19
+ <MSALProvider
20
+ clientId="..."
21
+ redirectUri="/auth/callback" // For redirect flow
22
+ popupRedirectUri="/blank.html" // For popup flow (default)
23
+ >
24
+ ```
25
+
26
+ **Benefits:**
27
+ - Use your custom redirect URI for redirect flow
28
+ - Popup always uses blank.html (no full app loading in popup)
29
+ - More flexible configuration
30
+
31
+ ## [3.1.4] - 2026-03-05
32
+
33
+ ### 🔧 Configuration Fix - Popup Redirect
34
+
35
+ **BREAKING CHANGE:** You must now create a `public/blank.html` file and configure it as a redirect URI in Azure AD.
36
+
37
+ **Why:** This prevents your full app from loading in the popup window after authentication.
38
+
39
+ **Setup Required:**
40
+
41
+ 1. Create `public/blank.html`:
42
+ ```html
43
+ <!DOCTYPE html>
44
+ <html>
45
+ <head><title>Auth</title></head>
46
+ <body></body>
47
+ </html>
48
+ ```
49
+
50
+ 2. Add to Azure AD redirect URIs:
51
+ - `http://localhost:3000/blank.html`
52
+ - `https://yourdomain.com/blank.html`
53
+
54
+ 3. Update your MSALProvider:
55
+ ```tsx
56
+ <MSALProvider
57
+ clientId="..."
58
+ redirectUri={typeof window !== 'undefined' ? `${window.location.origin}/blank.html` : undefined}
59
+ >
60
+ ```
61
+
62
+ **Changes:**
63
+ - Set `navigateToLoginRequestUrl` default to `false`
64
+ - Updated README with blank.html setup instructions
65
+ - Added PUBLIC_BLANK_HTML.md guide
66
+
67
+ ## [3.1.3] - 2026-03-05
68
+
69
+ ### 🐛 Critical Fix - Popup Redirect Issue
70
+
71
+ **Fixed:** Popup window now stays as popup and doesn't navigate to redirect URI.
72
+
73
+ **Changes:**
74
+ - Added `windowHashTimeout`, `iframeHashTimeout`, and `loadFrameTimeout` to MSAL config
75
+ - Set `redirectUri: undefined` in popup requests to prevent navigation
76
+ - Popup now properly closes after authentication without showing redirect page
77
+
78
+ **This fixes the issue where the redirect URI was opening inside the popup window instead of the popup closing.**
79
+
80
+ ## [3.1.2] - 2026-03-05
81
+
82
+ ### 📝 Documentation Update
83
+
84
+ - Updated README with current version number
85
+ - No code changes from 3.1.1
86
+
87
+ ## [3.1.1] - 2026-03-05
88
+
89
+ ### 📝 Documentation & Build
90
+
91
+ - Fixed landing page build issues
92
+ - Cleaned up redundant documentation files
93
+ - Updated package files list
94
+ - No code changes from 3.0.8
95
+
5
96
  ## [3.0.8] - 2026-03-05
6
97
 
7
98
  ### 🚨 CRITICAL BUG FIX
package/README.md CHANGED
@@ -5,11 +5,11 @@ Production-grade MSAL authentication library for Next.js App Router with minimal
5
5
  [![npm version](https://badge.fury.io/js/@chemmangat%2Fmsal-next.svg)](https://www.npmjs.com/package/@chemmangat/msal-next)
6
6
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
7
 
8
- > **📦 Current Version: 3.0.8** - Critical bug fixes for popup authentication. [See changelog](./CHANGELOG.md)
8
+ > **📦 Current Version: 3.1.5** - Separate popup redirect URI support. [See changelog](./CHANGELOG.md)
9
9
 
10
10
  > **⚠️ Important:** If you're on v3.0.6 or v3.0.7, please update immediately - those versions have a critical popup authentication bug.
11
11
 
12
- > **Having issues?** Check the [Troubleshooting Guide](./TROUBLESHOOTING.md) for common problems and solutions.
12
+ > **💡 Having issues?** Check the [Troubleshooting Guide](./TROUBLESHOOTING.md) for common problems and solutions.
13
13
 
14
14
  ## Features
15
15
 
@@ -91,7 +91,23 @@ npm install @chemmangat/msal-next@latest @azure/msal-browser@^4.0.0 @azure/msal-
91
91
 
92
92
  > **Important:** Use `MSALProvider` (not `MsalAuthProvider`) in your layout.tsx to avoid the "createContext only works in Client Components" error.
93
93
 
94
- ### 1. Wrap your app with MSALProvider
94
+ ### 1. Create blank.html for popup authentication
95
+
96
+ Create `public/blank.html`:
97
+
98
+ ```html
99
+ <!DOCTYPE html>
100
+ <html>
101
+ <head><title>Auth</title></head>
102
+ <body></body>
103
+ </html>
104
+ ```
105
+
106
+ Add to Azure AD redirect URIs:
107
+ - `http://localhost:3000/blank.html`
108
+ - `https://yourdomain.com/blank.html`
109
+
110
+ ### 2. Wrap your app with MSALProvider
95
111
 
96
112
  ```tsx
97
113
  // app/layout.tsx
@@ -104,6 +120,9 @@ export default function RootLayout({ children }) {
104
120
  <MSALProvider
105
121
  clientId={process.env.NEXT_PUBLIC_AZURE_AD_CLIENT_ID!}
106
122
  tenantId={process.env.NEXT_PUBLIC_AZURE_AD_TENANT_ID!}
123
+ // Optional: specify custom redirect URIs
124
+ // redirectUri="/auth/callback" // For redirect flow
125
+ // popupRedirectUri="/blank.html" // For popup flow (default)
107
126
  >
108
127
  {children}
109
128
  </MSALProvider>
@@ -113,7 +132,7 @@ export default function RootLayout({ children }) {
113
132
  }
114
133
  ```
115
134
 
116
- ### 2. Add sign-in button
135
+ ### 3. Add sign-in button
117
136
 
118
137
  ```tsx
119
138
  // app/page.tsx
package/dist/index.d.mts CHANGED
@@ -41,6 +41,12 @@ interface MsalAuthConfig {
41
41
  * @default window.location.origin
42
42
  */
43
43
  redirectUri?: string;
44
+ /**
45
+ * Redirect URI for popup authentication (recommended: /blank.html)
46
+ * If not specified, uses redirectUri
47
+ * @default redirectUri
48
+ */
49
+ popupRedirectUri?: string;
44
50
  /**
45
51
  * Post logout redirect URI
46
52
  * @default redirectUri
@@ -103,7 +109,7 @@ interface MsalAuthProviderProps extends MsalAuthConfig {
103
109
  * @returns The MSAL instance or null if not initialized
104
110
  */
105
111
  declare function getMsalInstance(): PublicClientApplication | null;
106
- declare function MsalAuthProvider({ children, loadingComponent, onInitialized, ...config }: MsalAuthProviderProps): react_jsx_runtime.JSX.Element;
112
+ declare function MsalAuthProvider({ children, loadingComponent, onInitialized, ...config }: MsalAuthProviderProps): react_jsx_runtime.JSX.Element | null;
107
113
 
108
114
  /**
109
115
  * Pre-configured MSALProvider component for Next.js App Router layouts.
@@ -584,6 +590,7 @@ interface UseRolesReturn {
584
590
  */
585
591
  declare function useRoles(): UseRolesReturn;
586
592
 
593
+ declare function getPopupRedirectUri(): string | undefined;
587
594
  declare function createMsalConfig(config: MsalAuthConfig): Configuration;
588
595
 
589
596
  interface WithAuthOptions extends Omit<AuthGuardProps, 'children'> {
@@ -931,4 +938,4 @@ interface ServerSession {
931
938
  accessToken?: string;
932
939
  }
933
940
 
934
- export { AuthGuard, type AuthGuardProps, type AuthMiddlewareConfig, AuthStatus, type AuthStatusProps, type CustomTokenClaims, type DebugLoggerConfig, ErrorBoundary, type ErrorBoundaryProps, type GraphApiOptions, MSALProvider, MicrosoftSignInButton, type MicrosoftSignInButtonProps, type MsalAuthConfig, MsalAuthProvider, type MsalAuthProviderProps, type RetryConfig, type ServerSession, SignOutButton, type SignOutButtonProps, type UseGraphApiReturn, type UseMsalAuthReturn, type UseRolesReturn, type UseUserProfileReturn, UserAvatar, type UserAvatarProps, type UserProfile, type ValidatedAccountData, type WithAuthOptions, createAuthMiddleware, createMsalConfig, createRetryWrapper, createScopedLogger, getDebugLogger, getMsalInstance, isValidAccountData, isValidRedirectUri, isValidScope, retryWithBackoff, safeJsonParse, sanitizeError, useGraphApi, useMsalAuth, useRoles, useUserProfile, validateScopes, withAuth };
941
+ export { AuthGuard, type AuthGuardProps, type AuthMiddlewareConfig, AuthStatus, type AuthStatusProps, type CustomTokenClaims, type DebugLoggerConfig, ErrorBoundary, type ErrorBoundaryProps, type GraphApiOptions, MSALProvider, MicrosoftSignInButton, type MicrosoftSignInButtonProps, type MsalAuthConfig, MsalAuthProvider, type MsalAuthProviderProps, type RetryConfig, type ServerSession, SignOutButton, type SignOutButtonProps, type UseGraphApiReturn, type UseMsalAuthReturn, type UseRolesReturn, type UseUserProfileReturn, UserAvatar, type UserAvatarProps, type UserProfile, type ValidatedAccountData, type WithAuthOptions, createAuthMiddleware, createMsalConfig, createRetryWrapper, createScopedLogger, getDebugLogger, getMsalInstance, getPopupRedirectUri, isValidAccountData, isValidRedirectUri, isValidScope, retryWithBackoff, safeJsonParse, sanitizeError, useGraphApi, useMsalAuth, useRoles, useUserProfile, validateScopes, withAuth };
package/dist/index.d.ts CHANGED
@@ -41,6 +41,12 @@ interface MsalAuthConfig {
41
41
  * @default window.location.origin
42
42
  */
43
43
  redirectUri?: string;
44
+ /**
45
+ * Redirect URI for popup authentication (recommended: /blank.html)
46
+ * If not specified, uses redirectUri
47
+ * @default redirectUri
48
+ */
49
+ popupRedirectUri?: string;
44
50
  /**
45
51
  * Post logout redirect URI
46
52
  * @default redirectUri
@@ -103,7 +109,7 @@ interface MsalAuthProviderProps extends MsalAuthConfig {
103
109
  * @returns The MSAL instance or null if not initialized
104
110
  */
105
111
  declare function getMsalInstance(): PublicClientApplication | null;
106
- declare function MsalAuthProvider({ children, loadingComponent, onInitialized, ...config }: MsalAuthProviderProps): react_jsx_runtime.JSX.Element;
112
+ declare function MsalAuthProvider({ children, loadingComponent, onInitialized, ...config }: MsalAuthProviderProps): react_jsx_runtime.JSX.Element | null;
107
113
 
108
114
  /**
109
115
  * Pre-configured MSALProvider component for Next.js App Router layouts.
@@ -584,6 +590,7 @@ interface UseRolesReturn {
584
590
  */
585
591
  declare function useRoles(): UseRolesReturn;
586
592
 
593
+ declare function getPopupRedirectUri(): string | undefined;
587
594
  declare function createMsalConfig(config: MsalAuthConfig): Configuration;
588
595
 
589
596
  interface WithAuthOptions extends Omit<AuthGuardProps, 'children'> {
@@ -931,4 +938,4 @@ interface ServerSession {
931
938
  accessToken?: string;
932
939
  }
933
940
 
934
- export { AuthGuard, type AuthGuardProps, type AuthMiddlewareConfig, AuthStatus, type AuthStatusProps, type CustomTokenClaims, type DebugLoggerConfig, ErrorBoundary, type ErrorBoundaryProps, type GraphApiOptions, MSALProvider, MicrosoftSignInButton, type MicrosoftSignInButtonProps, type MsalAuthConfig, MsalAuthProvider, type MsalAuthProviderProps, type RetryConfig, type ServerSession, SignOutButton, type SignOutButtonProps, type UseGraphApiReturn, type UseMsalAuthReturn, type UseRolesReturn, type UseUserProfileReturn, UserAvatar, type UserAvatarProps, type UserProfile, type ValidatedAccountData, type WithAuthOptions, createAuthMiddleware, createMsalConfig, createRetryWrapper, createScopedLogger, getDebugLogger, getMsalInstance, isValidAccountData, isValidRedirectUri, isValidScope, retryWithBackoff, safeJsonParse, sanitizeError, useGraphApi, useMsalAuth, useRoles, useUserProfile, validateScopes, withAuth };
941
+ export { AuthGuard, type AuthGuardProps, type AuthMiddlewareConfig, AuthStatus, type AuthStatusProps, type CustomTokenClaims, type DebugLoggerConfig, ErrorBoundary, type ErrorBoundaryProps, type GraphApiOptions, MSALProvider, MicrosoftSignInButton, type MicrosoftSignInButtonProps, type MsalAuthConfig, MsalAuthProvider, type MsalAuthProviderProps, type RetryConfig, type ServerSession, SignOutButton, type SignOutButtonProps, type UseGraphApiReturn, type UseMsalAuthReturn, type UseRolesReturn, type UseUserProfileReturn, UserAvatar, type UserAvatarProps, type UserProfile, type ValidatedAccountData, type WithAuthOptions, createAuthMiddleware, createMsalConfig, createRetryWrapper, createScopedLogger, getDebugLogger, getMsalInstance, getPopupRedirectUri, isValidAccountData, isValidRedirectUri, isValidScope, retryWithBackoff, safeJsonParse, sanitizeError, useGraphApi, useMsalAuth, useRoles, useUserProfile, validateScopes, withAuth };
package/dist/index.js CHANGED
@@ -35,6 +35,7 @@ __export(client_exports, {
35
35
  createScopedLogger: () => createScopedLogger,
36
36
  getDebugLogger: () => getDebugLogger,
37
37
  getMsalInstance: () => getMsalInstance,
38
+ getPopupRedirectUri: () => getPopupRedirectUri,
38
39
  isValidAccountData: () => isValidAccountData,
39
40
  isValidRedirectUri: () => isValidRedirectUri,
40
41
  isValidScope: () => isValidScope,
@@ -105,6 +106,10 @@ function validateScopes(scopes) {
105
106
  }
106
107
 
107
108
  // src/utils/createMsalConfig.ts
109
+ var storedPopupRedirectUri;
110
+ function getPopupRedirectUri() {
111
+ return storedPopupRedirectUri;
112
+ }
108
113
  function createMsalConfig(config) {
109
114
  if (config.msalConfig) {
110
115
  return config.msalConfig;
@@ -114,10 +119,11 @@ function createMsalConfig(config) {
114
119
  tenantId,
115
120
  authorityType = "common",
116
121
  redirectUri,
122
+ popupRedirectUri,
117
123
  postLogoutRedirectUri,
118
124
  cacheLocation = "sessionStorage",
119
125
  storeAuthStateInCookie = false,
120
- navigateToLoginRequestUrl = true,
126
+ navigateToLoginRequestUrl = false,
121
127
  enableLogging = false,
122
128
  loggerCallback,
123
129
  allowedRedirectUris
@@ -136,6 +142,9 @@ function createMsalConfig(config) {
136
142
  };
137
143
  const defaultRedirectUri = typeof window !== "undefined" ? window.location.origin : "http://localhost:3000";
138
144
  const finalRedirectUri = redirectUri || defaultRedirectUri;
145
+ const defaultPopupRedirectUri = typeof window !== "undefined" ? `${window.location.origin}/blank.html` : "http://localhost:3000/blank.html";
146
+ const finalPopupRedirectUri = popupRedirectUri || defaultPopupRedirectUri;
147
+ storedPopupRedirectUri = finalPopupRedirectUri;
139
148
  if (allowedRedirectUris && allowedRedirectUris.length > 0) {
140
149
  if (!isValidRedirectUri(finalRedirectUri, allowedRedirectUris)) {
141
150
  throw new Error(
@@ -162,6 +171,10 @@ function createMsalConfig(config) {
162
171
  storeAuthStateInCookie
163
172
  },
164
173
  system: {
174
+ windowHashTimeout: 6e4,
175
+ // Increase timeout for popup
176
+ iframeHashTimeout: 6e3,
177
+ loadFrameTimeout: 0,
165
178
  loggerOptions: {
166
179
  loggerCallback: loggerCallback || ((level, message, containsPii) => {
167
180
  if (containsPii || !enableLogging) return;
@@ -200,6 +213,13 @@ function MsalAuthProvider({ children, loadingComponent, onInitialized, ...config
200
213
  if (typeof window === "undefined") {
201
214
  return;
202
215
  }
216
+ const isInPopup2 = window.opener && window.opener !== window;
217
+ if (isInPopup2) {
218
+ if (config.enableLogging) {
219
+ console.log("[MSAL] Detected popup window - minimal initialization");
220
+ }
221
+ return;
222
+ }
203
223
  if (instanceRef.current) {
204
224
  return;
205
225
  }
@@ -208,17 +228,17 @@ function MsalAuthProvider({ children, loadingComponent, onInitialized, ...config
208
228
  const msalConfig = createMsalConfig(config);
209
229
  const instance = new import_msal_browser2.PublicClientApplication(msalConfig);
210
230
  await instance.initialize();
211
- const isInPopup = window.opener && window.opener !== window;
231
+ const isInPopup3 = window.opener && window.opener !== window;
212
232
  try {
213
233
  const response = await instance.handleRedirectPromise();
214
234
  if (response) {
215
235
  if (config.enableLogging) {
216
- console.log("[MSAL] Redirect authentication successful", isInPopup ? "(popup)" : "(main)");
236
+ console.log("[MSAL] Redirect authentication successful", isInPopup3 ? "(popup)" : "(main)");
217
237
  }
218
238
  if (response.account) {
219
239
  instance.setActiveAccount(response.account);
220
240
  }
221
- if (!isInPopup && window.location.hash) {
241
+ if (!isInPopup3 && window.location.hash) {
222
242
  window.history.replaceState(null, "", window.location.pathname + window.location.search);
223
243
  }
224
244
  }
@@ -234,7 +254,7 @@ function MsalAuthProvider({ children, loadingComponent, onInitialized, ...config
234
254
  } else {
235
255
  console.error("[MSAL] Redirect handling error:", redirectError);
236
256
  }
237
- if (!isInPopup && window.location.hash && (window.location.hash.includes("code=") || window.location.hash.includes("error="))) {
257
+ if (!isInPopup3 && window.location.hash && (window.location.hash.includes("code=") || window.location.hash.includes("error="))) {
238
258
  window.history.replaceState(null, "", window.location.pathname + window.location.search);
239
259
  }
240
260
  }
@@ -290,6 +310,10 @@ function MsalAuthProvider({ children, loadingComponent, onInitialized, ...config
290
310
  if (typeof window === "undefined") {
291
311
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: loadingComponent || /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { children: "Loading authentication..." }) });
292
312
  }
313
+ const isInPopup = window.opener && window.opener !== window;
314
+ if (isInPopup) {
315
+ return null;
316
+ }
293
317
  if (!msalInstance) {
294
318
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: loadingComponent || /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { children: "Loading authentication..." }) });
295
319
  }
@@ -319,9 +343,12 @@ function useMsalAuth(defaultScopes = ["User.Read"]) {
319
343
  return;
320
344
  }
321
345
  try {
346
+ const popupRedirectUri = getPopupRedirectUri();
322
347
  const request = {
323
348
  scopes,
324
- prompt: "select_account"
349
+ prompt: "select_account",
350
+ // Use popup-specific redirect URI (defaults to /blank.html)
351
+ redirectUri: popupRedirectUri
325
352
  };
326
353
  const response = await instance.loginPopup(request);
327
354
  if (response?.account) {
@@ -1682,6 +1709,7 @@ var import_msal_react3 = require("@azure/msal-react");
1682
1709
  createScopedLogger,
1683
1710
  getDebugLogger,
1684
1711
  getMsalInstance,
1712
+ getPopupRedirectUri,
1685
1713
  isValidAccountData,
1686
1714
  isValidRedirectUri,
1687
1715
  isValidScope,
package/dist/index.mjs CHANGED
@@ -52,6 +52,10 @@ function validateScopes(scopes) {
52
52
  }
53
53
 
54
54
  // src/utils/createMsalConfig.ts
55
+ var storedPopupRedirectUri;
56
+ function getPopupRedirectUri() {
57
+ return storedPopupRedirectUri;
58
+ }
55
59
  function createMsalConfig(config) {
56
60
  if (config.msalConfig) {
57
61
  return config.msalConfig;
@@ -61,10 +65,11 @@ function createMsalConfig(config) {
61
65
  tenantId,
62
66
  authorityType = "common",
63
67
  redirectUri,
68
+ popupRedirectUri,
64
69
  postLogoutRedirectUri,
65
70
  cacheLocation = "sessionStorage",
66
71
  storeAuthStateInCookie = false,
67
- navigateToLoginRequestUrl = true,
72
+ navigateToLoginRequestUrl = false,
68
73
  enableLogging = false,
69
74
  loggerCallback,
70
75
  allowedRedirectUris
@@ -83,6 +88,9 @@ function createMsalConfig(config) {
83
88
  };
84
89
  const defaultRedirectUri = typeof window !== "undefined" ? window.location.origin : "http://localhost:3000";
85
90
  const finalRedirectUri = redirectUri || defaultRedirectUri;
91
+ const defaultPopupRedirectUri = typeof window !== "undefined" ? `${window.location.origin}/blank.html` : "http://localhost:3000/blank.html";
92
+ const finalPopupRedirectUri = popupRedirectUri || defaultPopupRedirectUri;
93
+ storedPopupRedirectUri = finalPopupRedirectUri;
86
94
  if (allowedRedirectUris && allowedRedirectUris.length > 0) {
87
95
  if (!isValidRedirectUri(finalRedirectUri, allowedRedirectUris)) {
88
96
  throw new Error(
@@ -109,6 +117,10 @@ function createMsalConfig(config) {
109
117
  storeAuthStateInCookie
110
118
  },
111
119
  system: {
120
+ windowHashTimeout: 6e4,
121
+ // Increase timeout for popup
122
+ iframeHashTimeout: 6e3,
123
+ loadFrameTimeout: 0,
112
124
  loggerOptions: {
113
125
  loggerCallback: loggerCallback || ((level, message, containsPii) => {
114
126
  if (containsPii || !enableLogging) return;
@@ -147,6 +159,13 @@ function MsalAuthProvider({ children, loadingComponent, onInitialized, ...config
147
159
  if (typeof window === "undefined") {
148
160
  return;
149
161
  }
162
+ const isInPopup2 = window.opener && window.opener !== window;
163
+ if (isInPopup2) {
164
+ if (config.enableLogging) {
165
+ console.log("[MSAL] Detected popup window - minimal initialization");
166
+ }
167
+ return;
168
+ }
150
169
  if (instanceRef.current) {
151
170
  return;
152
171
  }
@@ -155,17 +174,17 @@ function MsalAuthProvider({ children, loadingComponent, onInitialized, ...config
155
174
  const msalConfig = createMsalConfig(config);
156
175
  const instance = new PublicClientApplication(msalConfig);
157
176
  await instance.initialize();
158
- const isInPopup = window.opener && window.opener !== window;
177
+ const isInPopup3 = window.opener && window.opener !== window;
159
178
  try {
160
179
  const response = await instance.handleRedirectPromise();
161
180
  if (response) {
162
181
  if (config.enableLogging) {
163
- console.log("[MSAL] Redirect authentication successful", isInPopup ? "(popup)" : "(main)");
182
+ console.log("[MSAL] Redirect authentication successful", isInPopup3 ? "(popup)" : "(main)");
164
183
  }
165
184
  if (response.account) {
166
185
  instance.setActiveAccount(response.account);
167
186
  }
168
- if (!isInPopup && window.location.hash) {
187
+ if (!isInPopup3 && window.location.hash) {
169
188
  window.history.replaceState(null, "", window.location.pathname + window.location.search);
170
189
  }
171
190
  }
@@ -181,7 +200,7 @@ function MsalAuthProvider({ children, loadingComponent, onInitialized, ...config
181
200
  } else {
182
201
  console.error("[MSAL] Redirect handling error:", redirectError);
183
202
  }
184
- if (!isInPopup && window.location.hash && (window.location.hash.includes("code=") || window.location.hash.includes("error="))) {
203
+ if (!isInPopup3 && window.location.hash && (window.location.hash.includes("code=") || window.location.hash.includes("error="))) {
185
204
  window.history.replaceState(null, "", window.location.pathname + window.location.search);
186
205
  }
187
206
  }
@@ -237,6 +256,10 @@ function MsalAuthProvider({ children, loadingComponent, onInitialized, ...config
237
256
  if (typeof window === "undefined") {
238
257
  return /* @__PURE__ */ jsx(Fragment, { children: loadingComponent || /* @__PURE__ */ jsx("div", { children: "Loading authentication..." }) });
239
258
  }
259
+ const isInPopup = window.opener && window.opener !== window;
260
+ if (isInPopup) {
261
+ return null;
262
+ }
240
263
  if (!msalInstance) {
241
264
  return /* @__PURE__ */ jsx(Fragment, { children: loadingComponent || /* @__PURE__ */ jsx("div", { children: "Loading authentication..." }) });
242
265
  }
@@ -266,9 +289,12 @@ function useMsalAuth(defaultScopes = ["User.Read"]) {
266
289
  return;
267
290
  }
268
291
  try {
292
+ const popupRedirectUri = getPopupRedirectUri();
269
293
  const request = {
270
294
  scopes,
271
- prompt: "select_account"
295
+ prompt: "select_account",
296
+ // Use popup-specific redirect URI (defaults to /blank.html)
297
+ redirectUri: popupRedirectUri
272
298
  };
273
299
  const response = await instance.loginPopup(request);
274
300
  if (response?.account) {
@@ -1628,6 +1654,7 @@ export {
1628
1654
  createScopedLogger,
1629
1655
  getDebugLogger,
1630
1656
  getMsalInstance,
1657
+ getPopupRedirectUri,
1631
1658
  isValidAccountData,
1632
1659
  isValidRedirectUri,
1633
1660
  isValidScope,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chemmangat/msal-next",
3
- "version": "3.1.1",
3
+ "version": "3.1.5",
4
4
  "description": "Production-grade MSAL authentication package for Next.js App Router with minimal boilerplate",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",