@chemmangat/msal-next 3.1.5 → 3.1.7
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 +40 -17
- package/README.md +10 -30
- package/dist/index.d.mts +7 -40
- package/dist/index.d.ts +7 -40
- package/dist/index.js +14 -122
- package/dist/index.mjs +15 -122
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,31 +2,54 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
-
## [3.1.
|
|
5
|
+
## [3.1.6] - 2026-03-05
|
|
6
6
|
|
|
7
|
-
###
|
|
7
|
+
### 🔄 Breaking Change - Redirect-Only Flow
|
|
8
8
|
|
|
9
|
-
**
|
|
9
|
+
**Removed all popup authentication support** - Package now only supports redirect flow for cleaner, simpler authentication.
|
|
10
10
|
|
|
11
|
-
**
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
11
|
+
**Why this change?**
|
|
12
|
+
- Popup flow had persistent issues (full app loading in popup, logout popups, etc.)
|
|
13
|
+
- Redirect flow is simpler, more reliable, and works out of the box
|
|
14
|
+
- No need for blank.html or special Azure AD configuration
|
|
15
|
+
- Better user experience with full-page redirects
|
|
16
|
+
|
|
17
|
+
**What was removed:**
|
|
18
|
+
- `loginPopup()` method
|
|
19
|
+
- `logoutPopup()` method
|
|
20
|
+
- `acquireTokenPopup()` method
|
|
21
|
+
- `useRedirect` prop from MicrosoftSignInButton
|
|
22
|
+
- `useRedirect` prop from SignOutButton
|
|
23
|
+
- `popupRedirectUri` configuration option
|
|
24
|
+
- `getPopupRedirectUri()` utility
|
|
25
|
+
- All popup-related code and configuration
|
|
26
|
+
|
|
27
|
+
**Migration:**
|
|
16
28
|
|
|
17
|
-
**Usage:**
|
|
18
29
|
```tsx
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
30
|
+
// Before (v3.1.4 and earlier)
|
|
31
|
+
const { loginPopup, logoutPopup } = useMsalAuth();
|
|
32
|
+
await loginPopup();
|
|
33
|
+
await logoutPopup();
|
|
34
|
+
|
|
35
|
+
<MicrosoftSignInButton useRedirect={false} />
|
|
36
|
+
<SignOutButton useRedirect={false} />
|
|
37
|
+
|
|
38
|
+
// After (v3.1.5) - redirect only
|
|
39
|
+
const { loginRedirect, logoutRedirect } = useMsalAuth();
|
|
40
|
+
await loginRedirect();
|
|
41
|
+
await logoutRedirect();
|
|
42
|
+
|
|
43
|
+
<MicrosoftSignInButton />
|
|
44
|
+
<SignOutButton />
|
|
24
45
|
```
|
|
25
46
|
|
|
26
47
|
**Benefits:**
|
|
27
|
-
-
|
|
28
|
-
-
|
|
29
|
-
-
|
|
48
|
+
- Simpler API - no popup vs redirect decisions
|
|
49
|
+
- No popup-related bugs or issues
|
|
50
|
+
- Works perfectly out of the box
|
|
51
|
+
- Cleaner codebase and smaller bundle size
|
|
52
|
+
- Better user experience
|
|
30
53
|
|
|
31
54
|
## [3.1.4] - 2026-03-05
|
|
32
55
|
|
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@ Production-grade MSAL authentication library for Next.js App Router with minimal
|
|
|
5
5
|
[](https://www.npmjs.com/package/@chemmangat/msal-next)
|
|
6
6
|
[](https://opensource.org/licenses/MIT)
|
|
7
7
|
|
|
8
|
-
> **📦 Current Version: 3.1.
|
|
8
|
+
> **📦 Current Version: 3.1.6** - Redirect-only authentication (popup support removed). [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
|
|
|
@@ -91,23 +91,7 @@ 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.
|
|
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
|
|
94
|
+
### 1. Wrap your app with MSALProvider
|
|
111
95
|
|
|
112
96
|
```tsx
|
|
113
97
|
// app/layout.tsx
|
|
@@ -120,9 +104,6 @@ export default function RootLayout({ children }) {
|
|
|
120
104
|
<MSALProvider
|
|
121
105
|
clientId={process.env.NEXT_PUBLIC_AZURE_AD_CLIENT_ID!}
|
|
122
106
|
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)
|
|
126
107
|
>
|
|
127
108
|
{children}
|
|
128
109
|
</MSALProvider>
|
|
@@ -132,7 +113,7 @@ export default function RootLayout({ children }) {
|
|
|
132
113
|
}
|
|
133
114
|
```
|
|
134
115
|
|
|
135
|
-
###
|
|
116
|
+
### 2. Add sign-in button
|
|
136
117
|
|
|
137
118
|
```tsx
|
|
138
119
|
// app/page.tsx
|
|
@@ -153,6 +134,8 @@ export default function Home() {
|
|
|
153
134
|
|
|
154
135
|
That's it! 🎉
|
|
155
136
|
|
|
137
|
+
The button uses redirect flow (full page redirect to Microsoft login, then back to your app). Simple and clean.
|
|
138
|
+
|
|
156
139
|
## Components
|
|
157
140
|
|
|
158
141
|
### MSALProvider (Recommended for App Router)
|
|
@@ -205,13 +188,12 @@ export function MyProviders({ children }) {
|
|
|
205
188
|
|
|
206
189
|
### MicrosoftSignInButton
|
|
207
190
|
|
|
208
|
-
Pre-styled sign-in button with Microsoft branding.
|
|
191
|
+
Pre-styled sign-in button with Microsoft branding. Uses redirect flow (full page redirect to Microsoft login).
|
|
209
192
|
|
|
210
193
|
```tsx
|
|
211
194
|
<MicrosoftSignInButton
|
|
212
195
|
variant="dark" // or "light"
|
|
213
196
|
size="medium" // "small", "medium", "large"
|
|
214
|
-
useRedirect={false} // Use popup by default
|
|
215
197
|
onSuccess={() => console.log('Signed in!')}
|
|
216
198
|
/>
|
|
217
199
|
```
|
|
@@ -294,21 +276,19 @@ const {
|
|
|
294
276
|
account,
|
|
295
277
|
isAuthenticated,
|
|
296
278
|
inProgress,
|
|
297
|
-
loginPopup,
|
|
298
279
|
loginRedirect,
|
|
299
|
-
logoutPopup,
|
|
300
280
|
logoutRedirect,
|
|
301
281
|
acquireToken,
|
|
302
282
|
} = useMsalAuth();
|
|
303
283
|
|
|
304
|
-
// Login
|
|
305
|
-
await
|
|
284
|
+
// Login (redirects to Microsoft)
|
|
285
|
+
await loginRedirect(['User.Read']);
|
|
306
286
|
|
|
307
287
|
// Get token
|
|
308
288
|
const token = await acquireToken(['User.Read']);
|
|
309
289
|
|
|
310
|
-
// Logout
|
|
311
|
-
await
|
|
290
|
+
// Logout (redirects to Microsoft)
|
|
291
|
+
await logoutRedirect();
|
|
312
292
|
```
|
|
313
293
|
|
|
314
294
|
### useGraphApi
|
package/dist/index.d.mts
CHANGED
|
@@ -41,12 +41,6 @@ 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;
|
|
50
44
|
/**
|
|
51
45
|
* Post logout redirect URI
|
|
52
46
|
* @default redirectUri
|
|
@@ -109,7 +103,7 @@ interface MsalAuthProviderProps extends MsalAuthConfig {
|
|
|
109
103
|
* @returns The MSAL instance or null if not initialized
|
|
110
104
|
*/
|
|
111
105
|
declare function getMsalInstance(): PublicClientApplication | null;
|
|
112
|
-
declare function MsalAuthProvider({ children, loadingComponent, onInitialized, ...config }: MsalAuthProviderProps): react_jsx_runtime.JSX.Element
|
|
106
|
+
declare function MsalAuthProvider({ children, loadingComponent, onInitialized, ...config }: MsalAuthProviderProps): react_jsx_runtime.JSX.Element;
|
|
113
107
|
|
|
114
108
|
/**
|
|
115
109
|
* Pre-configured MSALProvider component for Next.js App Router layouts.
|
|
@@ -155,11 +149,6 @@ interface MicrosoftSignInButtonProps {
|
|
|
155
149
|
* @default 'medium'
|
|
156
150
|
*/
|
|
157
151
|
size?: 'small' | 'medium' | 'large';
|
|
158
|
-
/**
|
|
159
|
-
* Use redirect flow instead of popup
|
|
160
|
-
* @default false
|
|
161
|
-
*/
|
|
162
|
-
useRedirect?: boolean;
|
|
163
152
|
/**
|
|
164
153
|
* Scopes to request
|
|
165
154
|
*/
|
|
@@ -181,7 +170,7 @@ interface MicrosoftSignInButtonProps {
|
|
|
181
170
|
*/
|
|
182
171
|
onError?: (error: Error) => void;
|
|
183
172
|
}
|
|
184
|
-
declare function MicrosoftSignInButton({ text, variant, size,
|
|
173
|
+
declare function MicrosoftSignInButton({ text, variant, size, scopes, className, style, onSuccess, onError, }: MicrosoftSignInButtonProps): react_jsx_runtime.JSX.Element;
|
|
185
174
|
|
|
186
175
|
interface SignOutButtonProps {
|
|
187
176
|
/**
|
|
@@ -199,11 +188,6 @@ interface SignOutButtonProps {
|
|
|
199
188
|
* @default 'medium'
|
|
200
189
|
*/
|
|
201
190
|
size?: 'small' | 'medium' | 'large';
|
|
202
|
-
/**
|
|
203
|
-
* Use redirect flow instead of popup
|
|
204
|
-
* @default false
|
|
205
|
-
*/
|
|
206
|
-
useRedirect?: boolean;
|
|
207
191
|
/**
|
|
208
192
|
* Custom className
|
|
209
193
|
*/
|
|
@@ -223,13 +207,14 @@ interface SignOutButtonProps {
|
|
|
223
207
|
}
|
|
224
208
|
/**
|
|
225
209
|
* SignOutButton component with Microsoft branding
|
|
210
|
+
* Uses redirect flow (full page redirect)
|
|
226
211
|
*
|
|
227
212
|
* @example
|
|
228
213
|
* ```tsx
|
|
229
214
|
* <SignOutButton variant="light" />
|
|
230
215
|
* ```
|
|
231
216
|
*/
|
|
232
|
-
declare function SignOutButton({ text, variant, size,
|
|
217
|
+
declare function SignOutButton({ text, variant, size, className, style, onSuccess, onError, }: SignOutButtonProps): react_jsx_runtime.JSX.Element;
|
|
233
218
|
|
|
234
219
|
interface UserAvatarProps {
|
|
235
220
|
/**
|
|
@@ -315,11 +300,6 @@ interface AuthGuardProps {
|
|
|
315
300
|
* Component to show when not authenticated (before redirect)
|
|
316
301
|
*/
|
|
317
302
|
fallbackComponent?: ReactNode;
|
|
318
|
-
/**
|
|
319
|
-
* Use redirect flow instead of popup
|
|
320
|
-
* @default true
|
|
321
|
-
*/
|
|
322
|
-
useRedirect?: boolean;
|
|
323
303
|
/**
|
|
324
304
|
* Scopes to request during authentication
|
|
325
305
|
*/
|
|
@@ -339,7 +319,7 @@ interface AuthGuardProps {
|
|
|
339
319
|
* </AuthGuard>
|
|
340
320
|
* ```
|
|
341
321
|
*/
|
|
342
|
-
declare function AuthGuard({ children, loadingComponent, fallbackComponent,
|
|
322
|
+
declare function AuthGuard({ children, loadingComponent, fallbackComponent, scopes, onAuthRequired, }: AuthGuardProps): react_jsx_runtime.JSX.Element;
|
|
343
323
|
|
|
344
324
|
interface ErrorBoundaryProps {
|
|
345
325
|
/**
|
|
@@ -401,34 +381,22 @@ interface UseMsalAuthReturn {
|
|
|
401
381
|
* Whether MSAL is currently performing an interaction
|
|
402
382
|
*/
|
|
403
383
|
inProgress: boolean;
|
|
404
|
-
/**
|
|
405
|
-
* Login using popup
|
|
406
|
-
*/
|
|
407
|
-
loginPopup: (scopes?: string[]) => Promise<void>;
|
|
408
384
|
/**
|
|
409
385
|
* Login using redirect
|
|
410
386
|
*/
|
|
411
387
|
loginRedirect: (scopes?: string[]) => Promise<void>;
|
|
412
|
-
/**
|
|
413
|
-
* Logout using popup
|
|
414
|
-
*/
|
|
415
|
-
logoutPopup: () => Promise<void>;
|
|
416
388
|
/**
|
|
417
389
|
* Logout using redirect
|
|
418
390
|
*/
|
|
419
391
|
logoutRedirect: () => Promise<void>;
|
|
420
392
|
/**
|
|
421
|
-
* Acquire access token silently
|
|
393
|
+
* Acquire access token silently
|
|
422
394
|
*/
|
|
423
395
|
acquireToken: (scopes: string[]) => Promise<string>;
|
|
424
396
|
/**
|
|
425
397
|
* Acquire access token silently only (no fallback)
|
|
426
398
|
*/
|
|
427
399
|
acquireTokenSilent: (scopes: string[]) => Promise<string>;
|
|
428
|
-
/**
|
|
429
|
-
* Acquire access token using popup
|
|
430
|
-
*/
|
|
431
|
-
acquireTokenPopup: (scopes: string[]) => Promise<string>;
|
|
432
400
|
/**
|
|
433
401
|
* Acquire access token using redirect
|
|
434
402
|
*/
|
|
@@ -590,7 +558,6 @@ interface UseRolesReturn {
|
|
|
590
558
|
*/
|
|
591
559
|
declare function useRoles(): UseRolesReturn;
|
|
592
560
|
|
|
593
|
-
declare function getPopupRedirectUri(): string | undefined;
|
|
594
561
|
declare function createMsalConfig(config: MsalAuthConfig): Configuration;
|
|
595
562
|
|
|
596
563
|
interface WithAuthOptions extends Omit<AuthGuardProps, 'children'> {
|
|
@@ -938,4 +905,4 @@ interface ServerSession {
|
|
|
938
905
|
accessToken?: string;
|
|
939
906
|
}
|
|
940
907
|
|
|
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,
|
|
908
|
+
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 };
|
package/dist/index.d.ts
CHANGED
|
@@ -41,12 +41,6 @@ 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;
|
|
50
44
|
/**
|
|
51
45
|
* Post logout redirect URI
|
|
52
46
|
* @default redirectUri
|
|
@@ -109,7 +103,7 @@ interface MsalAuthProviderProps extends MsalAuthConfig {
|
|
|
109
103
|
* @returns The MSAL instance or null if not initialized
|
|
110
104
|
*/
|
|
111
105
|
declare function getMsalInstance(): PublicClientApplication | null;
|
|
112
|
-
declare function MsalAuthProvider({ children, loadingComponent, onInitialized, ...config }: MsalAuthProviderProps): react_jsx_runtime.JSX.Element
|
|
106
|
+
declare function MsalAuthProvider({ children, loadingComponent, onInitialized, ...config }: MsalAuthProviderProps): react_jsx_runtime.JSX.Element;
|
|
113
107
|
|
|
114
108
|
/**
|
|
115
109
|
* Pre-configured MSALProvider component for Next.js App Router layouts.
|
|
@@ -155,11 +149,6 @@ interface MicrosoftSignInButtonProps {
|
|
|
155
149
|
* @default 'medium'
|
|
156
150
|
*/
|
|
157
151
|
size?: 'small' | 'medium' | 'large';
|
|
158
|
-
/**
|
|
159
|
-
* Use redirect flow instead of popup
|
|
160
|
-
* @default false
|
|
161
|
-
*/
|
|
162
|
-
useRedirect?: boolean;
|
|
163
152
|
/**
|
|
164
153
|
* Scopes to request
|
|
165
154
|
*/
|
|
@@ -181,7 +170,7 @@ interface MicrosoftSignInButtonProps {
|
|
|
181
170
|
*/
|
|
182
171
|
onError?: (error: Error) => void;
|
|
183
172
|
}
|
|
184
|
-
declare function MicrosoftSignInButton({ text, variant, size,
|
|
173
|
+
declare function MicrosoftSignInButton({ text, variant, size, scopes, className, style, onSuccess, onError, }: MicrosoftSignInButtonProps): react_jsx_runtime.JSX.Element;
|
|
185
174
|
|
|
186
175
|
interface SignOutButtonProps {
|
|
187
176
|
/**
|
|
@@ -199,11 +188,6 @@ interface SignOutButtonProps {
|
|
|
199
188
|
* @default 'medium'
|
|
200
189
|
*/
|
|
201
190
|
size?: 'small' | 'medium' | 'large';
|
|
202
|
-
/**
|
|
203
|
-
* Use redirect flow instead of popup
|
|
204
|
-
* @default false
|
|
205
|
-
*/
|
|
206
|
-
useRedirect?: boolean;
|
|
207
191
|
/**
|
|
208
192
|
* Custom className
|
|
209
193
|
*/
|
|
@@ -223,13 +207,14 @@ interface SignOutButtonProps {
|
|
|
223
207
|
}
|
|
224
208
|
/**
|
|
225
209
|
* SignOutButton component with Microsoft branding
|
|
210
|
+
* Uses redirect flow (full page redirect)
|
|
226
211
|
*
|
|
227
212
|
* @example
|
|
228
213
|
* ```tsx
|
|
229
214
|
* <SignOutButton variant="light" />
|
|
230
215
|
* ```
|
|
231
216
|
*/
|
|
232
|
-
declare function SignOutButton({ text, variant, size,
|
|
217
|
+
declare function SignOutButton({ text, variant, size, className, style, onSuccess, onError, }: SignOutButtonProps): react_jsx_runtime.JSX.Element;
|
|
233
218
|
|
|
234
219
|
interface UserAvatarProps {
|
|
235
220
|
/**
|
|
@@ -315,11 +300,6 @@ interface AuthGuardProps {
|
|
|
315
300
|
* Component to show when not authenticated (before redirect)
|
|
316
301
|
*/
|
|
317
302
|
fallbackComponent?: ReactNode;
|
|
318
|
-
/**
|
|
319
|
-
* Use redirect flow instead of popup
|
|
320
|
-
* @default true
|
|
321
|
-
*/
|
|
322
|
-
useRedirect?: boolean;
|
|
323
303
|
/**
|
|
324
304
|
* Scopes to request during authentication
|
|
325
305
|
*/
|
|
@@ -339,7 +319,7 @@ interface AuthGuardProps {
|
|
|
339
319
|
* </AuthGuard>
|
|
340
320
|
* ```
|
|
341
321
|
*/
|
|
342
|
-
declare function AuthGuard({ children, loadingComponent, fallbackComponent,
|
|
322
|
+
declare function AuthGuard({ children, loadingComponent, fallbackComponent, scopes, onAuthRequired, }: AuthGuardProps): react_jsx_runtime.JSX.Element;
|
|
343
323
|
|
|
344
324
|
interface ErrorBoundaryProps {
|
|
345
325
|
/**
|
|
@@ -401,34 +381,22 @@ interface UseMsalAuthReturn {
|
|
|
401
381
|
* Whether MSAL is currently performing an interaction
|
|
402
382
|
*/
|
|
403
383
|
inProgress: boolean;
|
|
404
|
-
/**
|
|
405
|
-
* Login using popup
|
|
406
|
-
*/
|
|
407
|
-
loginPopup: (scopes?: string[]) => Promise<void>;
|
|
408
384
|
/**
|
|
409
385
|
* Login using redirect
|
|
410
386
|
*/
|
|
411
387
|
loginRedirect: (scopes?: string[]) => Promise<void>;
|
|
412
|
-
/**
|
|
413
|
-
* Logout using popup
|
|
414
|
-
*/
|
|
415
|
-
logoutPopup: () => Promise<void>;
|
|
416
388
|
/**
|
|
417
389
|
* Logout using redirect
|
|
418
390
|
*/
|
|
419
391
|
logoutRedirect: () => Promise<void>;
|
|
420
392
|
/**
|
|
421
|
-
* Acquire access token silently
|
|
393
|
+
* Acquire access token silently
|
|
422
394
|
*/
|
|
423
395
|
acquireToken: (scopes: string[]) => Promise<string>;
|
|
424
396
|
/**
|
|
425
397
|
* Acquire access token silently only (no fallback)
|
|
426
398
|
*/
|
|
427
399
|
acquireTokenSilent: (scopes: string[]) => Promise<string>;
|
|
428
|
-
/**
|
|
429
|
-
* Acquire access token using popup
|
|
430
|
-
*/
|
|
431
|
-
acquireTokenPopup: (scopes: string[]) => Promise<string>;
|
|
432
400
|
/**
|
|
433
401
|
* Acquire access token using redirect
|
|
434
402
|
*/
|
|
@@ -590,7 +558,6 @@ interface UseRolesReturn {
|
|
|
590
558
|
*/
|
|
591
559
|
declare function useRoles(): UseRolesReturn;
|
|
592
560
|
|
|
593
|
-
declare function getPopupRedirectUri(): string | undefined;
|
|
594
561
|
declare function createMsalConfig(config: MsalAuthConfig): Configuration;
|
|
595
562
|
|
|
596
563
|
interface WithAuthOptions extends Omit<AuthGuardProps, 'children'> {
|
|
@@ -938,4 +905,4 @@ interface ServerSession {
|
|
|
938
905
|
accessToken?: string;
|
|
939
906
|
}
|
|
940
907
|
|
|
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,
|
|
908
|
+
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 };
|
package/dist/index.js
CHANGED
|
@@ -35,7 +35,6 @@ __export(client_exports, {
|
|
|
35
35
|
createScopedLogger: () => createScopedLogger,
|
|
36
36
|
getDebugLogger: () => getDebugLogger,
|
|
37
37
|
getMsalInstance: () => getMsalInstance,
|
|
38
|
-
getPopupRedirectUri: () => getPopupRedirectUri,
|
|
39
38
|
isValidAccountData: () => isValidAccountData,
|
|
40
39
|
isValidRedirectUri: () => isValidRedirectUri,
|
|
41
40
|
isValidScope: () => isValidScope,
|
|
@@ -106,10 +105,6 @@ function validateScopes(scopes) {
|
|
|
106
105
|
}
|
|
107
106
|
|
|
108
107
|
// src/utils/createMsalConfig.ts
|
|
109
|
-
var storedPopupRedirectUri;
|
|
110
|
-
function getPopupRedirectUri() {
|
|
111
|
-
return storedPopupRedirectUri;
|
|
112
|
-
}
|
|
113
108
|
function createMsalConfig(config) {
|
|
114
109
|
if (config.msalConfig) {
|
|
115
110
|
return config.msalConfig;
|
|
@@ -119,7 +114,6 @@ function createMsalConfig(config) {
|
|
|
119
114
|
tenantId,
|
|
120
115
|
authorityType = "common",
|
|
121
116
|
redirectUri,
|
|
122
|
-
popupRedirectUri,
|
|
123
117
|
postLogoutRedirectUri,
|
|
124
118
|
cacheLocation = "sessionStorage",
|
|
125
119
|
storeAuthStateInCookie = false,
|
|
@@ -142,9 +136,6 @@ function createMsalConfig(config) {
|
|
|
142
136
|
};
|
|
143
137
|
const defaultRedirectUri = typeof window !== "undefined" ? window.location.origin : "http://localhost:3000";
|
|
144
138
|
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;
|
|
148
139
|
if (allowedRedirectUris && allowedRedirectUris.length > 0) {
|
|
149
140
|
if (!isValidRedirectUri(finalRedirectUri, allowedRedirectUris)) {
|
|
150
141
|
throw new Error(
|
|
@@ -171,10 +162,6 @@ function createMsalConfig(config) {
|
|
|
171
162
|
storeAuthStateInCookie
|
|
172
163
|
},
|
|
173
164
|
system: {
|
|
174
|
-
windowHashTimeout: 6e4,
|
|
175
|
-
// Increase timeout for popup
|
|
176
|
-
iframeHashTimeout: 6e3,
|
|
177
|
-
loadFrameTimeout: 0,
|
|
178
165
|
loggerOptions: {
|
|
179
166
|
loggerCallback: loggerCallback || ((level, message, containsPii) => {
|
|
180
167
|
if (containsPii || !enableLogging) return;
|
|
@@ -213,13 +200,6 @@ function MsalAuthProvider({ children, loadingComponent, onInitialized, ...config
|
|
|
213
200
|
if (typeof window === "undefined") {
|
|
214
201
|
return;
|
|
215
202
|
}
|
|
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
|
-
}
|
|
223
203
|
if (instanceRef.current) {
|
|
224
204
|
return;
|
|
225
205
|
}
|
|
@@ -228,17 +208,16 @@ function MsalAuthProvider({ children, loadingComponent, onInitialized, ...config
|
|
|
228
208
|
const msalConfig = createMsalConfig(config);
|
|
229
209
|
const instance = new import_msal_browser2.PublicClientApplication(msalConfig);
|
|
230
210
|
await instance.initialize();
|
|
231
|
-
const isInPopup3 = window.opener && window.opener !== window;
|
|
232
211
|
try {
|
|
233
212
|
const response = await instance.handleRedirectPromise();
|
|
234
213
|
if (response) {
|
|
235
214
|
if (config.enableLogging) {
|
|
236
|
-
console.log("[MSAL] Redirect authentication successful"
|
|
215
|
+
console.log("[MSAL] Redirect authentication successful");
|
|
237
216
|
}
|
|
238
217
|
if (response.account) {
|
|
239
218
|
instance.setActiveAccount(response.account);
|
|
240
219
|
}
|
|
241
|
-
if (
|
|
220
|
+
if (window.location.hash) {
|
|
242
221
|
window.history.replaceState(null, "", window.location.pathname + window.location.search);
|
|
243
222
|
}
|
|
244
223
|
}
|
|
@@ -254,7 +233,7 @@ function MsalAuthProvider({ children, loadingComponent, onInitialized, ...config
|
|
|
254
233
|
} else {
|
|
255
234
|
console.error("[MSAL] Redirect handling error:", redirectError);
|
|
256
235
|
}
|
|
257
|
-
if (
|
|
236
|
+
if (window.location.hash && (window.location.hash.includes("code=") || window.location.hash.includes("error="))) {
|
|
258
237
|
window.history.replaceState(null, "", window.location.pathname + window.location.search);
|
|
259
238
|
}
|
|
260
239
|
}
|
|
@@ -310,10 +289,6 @@ function MsalAuthProvider({ children, loadingComponent, onInitialized, ...config
|
|
|
310
289
|
if (typeof window === "undefined") {
|
|
311
290
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: loadingComponent || /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { children: "Loading authentication..." }) });
|
|
312
291
|
}
|
|
313
|
-
const isInPopup = window.opener && window.opener !== window;
|
|
314
|
-
if (isInPopup) {
|
|
315
|
-
return null;
|
|
316
|
-
}
|
|
317
292
|
if (!msalInstance) {
|
|
318
293
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: loadingComponent || /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { children: "Loading authentication..." }) });
|
|
319
294
|
}
|
|
@@ -334,37 +309,7 @@ var pendingTokenRequests = /* @__PURE__ */ new Map();
|
|
|
334
309
|
function useMsalAuth(defaultScopes = ["User.Read"]) {
|
|
335
310
|
const { instance, accounts, inProgress } = (0, import_msal_react2.useMsal)();
|
|
336
311
|
const account = (0, import_msal_react2.useAccount)(accounts[0] || null);
|
|
337
|
-
const popupInProgressRef = (0, import_react2.useRef)(false);
|
|
338
312
|
const isAuthenticated = (0, import_react2.useMemo)(() => accounts.length > 0, [accounts]);
|
|
339
|
-
const loginPopup = (0, import_react2.useCallback)(
|
|
340
|
-
async (scopes = defaultScopes) => {
|
|
341
|
-
if (inProgress !== import_msal_browser3.InteractionStatus.None) {
|
|
342
|
-
console.warn("[MSAL] Interaction already in progress");
|
|
343
|
-
return;
|
|
344
|
-
}
|
|
345
|
-
try {
|
|
346
|
-
const popupRedirectUri = getPopupRedirectUri();
|
|
347
|
-
const request = {
|
|
348
|
-
scopes,
|
|
349
|
-
prompt: "select_account",
|
|
350
|
-
// Use popup-specific redirect URI (defaults to /blank.html)
|
|
351
|
-
redirectUri: popupRedirectUri
|
|
352
|
-
};
|
|
353
|
-
const response = await instance.loginPopup(request);
|
|
354
|
-
if (response?.account) {
|
|
355
|
-
instance.setActiveAccount(response.account);
|
|
356
|
-
}
|
|
357
|
-
} catch (error) {
|
|
358
|
-
if (error?.errorCode === "user_cancelled") {
|
|
359
|
-
console.log("[MSAL] User cancelled login");
|
|
360
|
-
return;
|
|
361
|
-
}
|
|
362
|
-
console.error("[MSAL] Login popup failed:", error);
|
|
363
|
-
throw error;
|
|
364
|
-
}
|
|
365
|
-
},
|
|
366
|
-
[instance, defaultScopes, inProgress]
|
|
367
|
-
);
|
|
368
313
|
const loginRedirect = (0, import_react2.useCallback)(
|
|
369
314
|
async (scopes = defaultScopes) => {
|
|
370
315
|
if (inProgress !== import_msal_browser3.InteractionStatus.None) {
|
|
@@ -388,16 +333,6 @@ function useMsalAuth(defaultScopes = ["User.Read"]) {
|
|
|
388
333
|
},
|
|
389
334
|
[instance, defaultScopes, inProgress]
|
|
390
335
|
);
|
|
391
|
-
const logoutPopup = (0, import_react2.useCallback)(async () => {
|
|
392
|
-
try {
|
|
393
|
-
await instance.logoutPopup({
|
|
394
|
-
account: account || void 0
|
|
395
|
-
});
|
|
396
|
-
} catch (error) {
|
|
397
|
-
console.error("[MSAL] Logout popup failed:", error);
|
|
398
|
-
throw error;
|
|
399
|
-
}
|
|
400
|
-
}, [instance, account]);
|
|
401
336
|
const logoutRedirect = (0, import_react2.useCallback)(async () => {
|
|
402
337
|
try {
|
|
403
338
|
await instance.logoutRedirect({
|
|
@@ -428,31 +363,6 @@ function useMsalAuth(defaultScopes = ["User.Read"]) {
|
|
|
428
363
|
},
|
|
429
364
|
[instance, account, defaultScopes]
|
|
430
365
|
);
|
|
431
|
-
const acquireTokenPopup = (0, import_react2.useCallback)(
|
|
432
|
-
async (scopes = defaultScopes) => {
|
|
433
|
-
if (!account) {
|
|
434
|
-
throw new Error("[MSAL] No active account. Please login first.");
|
|
435
|
-
}
|
|
436
|
-
if (popupInProgressRef.current) {
|
|
437
|
-
throw new Error("[MSAL] Popup already in progress. Please wait.");
|
|
438
|
-
}
|
|
439
|
-
try {
|
|
440
|
-
popupInProgressRef.current = true;
|
|
441
|
-
const request = {
|
|
442
|
-
scopes,
|
|
443
|
-
account
|
|
444
|
-
};
|
|
445
|
-
const response = await instance.acquireTokenPopup(request);
|
|
446
|
-
return response.accessToken;
|
|
447
|
-
} catch (error) {
|
|
448
|
-
console.error("[MSAL] Token popup acquisition failed:", error);
|
|
449
|
-
throw error;
|
|
450
|
-
} finally {
|
|
451
|
-
popupInProgressRef.current = false;
|
|
452
|
-
}
|
|
453
|
-
},
|
|
454
|
-
[instance, account, defaultScopes]
|
|
455
|
-
);
|
|
456
366
|
const acquireTokenRedirect = (0, import_react2.useCallback)(
|
|
457
367
|
async (scopes = defaultScopes) => {
|
|
458
368
|
if (!account) {
|
|
@@ -482,8 +392,9 @@ function useMsalAuth(defaultScopes = ["User.Read"]) {
|
|
|
482
392
|
try {
|
|
483
393
|
return await acquireTokenSilent(scopes);
|
|
484
394
|
} catch (error) {
|
|
485
|
-
console.warn("[MSAL] Silent token acquisition failed, falling back to
|
|
486
|
-
|
|
395
|
+
console.warn("[MSAL] Silent token acquisition failed, falling back to redirect");
|
|
396
|
+
await acquireTokenRedirect(scopes);
|
|
397
|
+
throw new Error("[MSAL] Redirecting for token acquisition");
|
|
487
398
|
} finally {
|
|
488
399
|
pendingTokenRequests.delete(requestKey);
|
|
489
400
|
}
|
|
@@ -491,7 +402,7 @@ function useMsalAuth(defaultScopes = ["User.Read"]) {
|
|
|
491
402
|
pendingTokenRequests.set(requestKey, tokenRequest);
|
|
492
403
|
return tokenRequest;
|
|
493
404
|
},
|
|
494
|
-
[acquireTokenSilent,
|
|
405
|
+
[acquireTokenSilent, acquireTokenRedirect, defaultScopes, account]
|
|
495
406
|
);
|
|
496
407
|
const clearSession = (0, import_react2.useCallback)(async () => {
|
|
497
408
|
instance.setActiveAccount(null);
|
|
@@ -502,13 +413,10 @@ function useMsalAuth(defaultScopes = ["User.Read"]) {
|
|
|
502
413
|
accounts,
|
|
503
414
|
isAuthenticated,
|
|
504
415
|
inProgress: inProgress !== import_msal_browser3.InteractionStatus.None,
|
|
505
|
-
loginPopup,
|
|
506
416
|
loginRedirect,
|
|
507
|
-
logoutPopup,
|
|
508
417
|
logoutRedirect,
|
|
509
418
|
acquireToken,
|
|
510
419
|
acquireTokenSilent,
|
|
511
|
-
acquireTokenPopup,
|
|
512
420
|
acquireTokenRedirect,
|
|
513
421
|
clearSession
|
|
514
422
|
};
|
|
@@ -521,23 +429,18 @@ function MicrosoftSignInButton({
|
|
|
521
429
|
text = "Sign in with Microsoft",
|
|
522
430
|
variant = "dark",
|
|
523
431
|
size = "medium",
|
|
524
|
-
useRedirect = false,
|
|
525
432
|
scopes,
|
|
526
433
|
className = "",
|
|
527
434
|
style,
|
|
528
435
|
onSuccess,
|
|
529
436
|
onError
|
|
530
437
|
}) {
|
|
531
|
-
const {
|
|
438
|
+
const { loginRedirect, inProgress } = useMsalAuth();
|
|
532
439
|
const [isLoading, setIsLoading] = (0, import_react3.useState)(false);
|
|
533
440
|
const handleClick = async () => {
|
|
534
441
|
setIsLoading(true);
|
|
535
442
|
try {
|
|
536
|
-
|
|
537
|
-
await loginRedirect(scopes);
|
|
538
|
-
} else {
|
|
539
|
-
await loginPopup(scopes);
|
|
540
|
-
}
|
|
443
|
+
await loginRedirect(scopes);
|
|
541
444
|
onSuccess?.();
|
|
542
445
|
} catch (error) {
|
|
543
446
|
onError?.(error);
|
|
@@ -620,20 +523,15 @@ function SignOutButton({
|
|
|
620
523
|
text = "Sign out",
|
|
621
524
|
variant = "dark",
|
|
622
525
|
size = "medium",
|
|
623
|
-
useRedirect = false,
|
|
624
526
|
className = "",
|
|
625
527
|
style,
|
|
626
528
|
onSuccess,
|
|
627
529
|
onError
|
|
628
530
|
}) {
|
|
629
|
-
const {
|
|
531
|
+
const { logoutRedirect, inProgress } = useMsalAuth();
|
|
630
532
|
const handleClick = async () => {
|
|
631
533
|
try {
|
|
632
|
-
|
|
633
|
-
await logoutRedirect();
|
|
634
|
-
} else {
|
|
635
|
-
await logoutPopup();
|
|
636
|
-
}
|
|
534
|
+
await logoutRedirect();
|
|
637
535
|
onSuccess?.();
|
|
638
536
|
} catch (error) {
|
|
639
537
|
onError?.(error);
|
|
@@ -1118,28 +1016,23 @@ function AuthGuard({
|
|
|
1118
1016
|
children,
|
|
1119
1017
|
loadingComponent,
|
|
1120
1018
|
fallbackComponent,
|
|
1121
|
-
useRedirect = true,
|
|
1122
1019
|
scopes,
|
|
1123
1020
|
onAuthRequired
|
|
1124
1021
|
}) {
|
|
1125
|
-
const { isAuthenticated, inProgress, loginRedirect
|
|
1022
|
+
const { isAuthenticated, inProgress, loginRedirect } = useMsalAuth();
|
|
1126
1023
|
(0, import_react7.useEffect)(() => {
|
|
1127
1024
|
if (!isAuthenticated && !inProgress) {
|
|
1128
1025
|
onAuthRequired?.();
|
|
1129
1026
|
const login = async () => {
|
|
1130
1027
|
try {
|
|
1131
|
-
|
|
1132
|
-
await loginRedirect(scopes);
|
|
1133
|
-
} else {
|
|
1134
|
-
await loginPopup(scopes);
|
|
1135
|
-
}
|
|
1028
|
+
await loginRedirect(scopes);
|
|
1136
1029
|
} catch (error) {
|
|
1137
1030
|
console.error("[AuthGuard] Authentication failed:", error);
|
|
1138
1031
|
}
|
|
1139
1032
|
};
|
|
1140
1033
|
login();
|
|
1141
1034
|
}
|
|
1142
|
-
}, [isAuthenticated, inProgress,
|
|
1035
|
+
}, [isAuthenticated, inProgress, scopes, loginRedirect, onAuthRequired]);
|
|
1143
1036
|
if (inProgress) {
|
|
1144
1037
|
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_jsx_runtime7.Fragment, { children: loadingComponent || /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { children: "Authenticating..." }) });
|
|
1145
1038
|
}
|
|
@@ -1709,7 +1602,6 @@ var import_msal_react3 = require("@azure/msal-react");
|
|
|
1709
1602
|
createScopedLogger,
|
|
1710
1603
|
getDebugLogger,
|
|
1711
1604
|
getMsalInstance,
|
|
1712
|
-
getPopupRedirectUri,
|
|
1713
1605
|
isValidAccountData,
|
|
1714
1606
|
isValidRedirectUri,
|
|
1715
1607
|
isValidScope,
|
package/dist/index.mjs
CHANGED
|
@@ -52,10 +52,6 @@ function validateScopes(scopes) {
|
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
// src/utils/createMsalConfig.ts
|
|
55
|
-
var storedPopupRedirectUri;
|
|
56
|
-
function getPopupRedirectUri() {
|
|
57
|
-
return storedPopupRedirectUri;
|
|
58
|
-
}
|
|
59
55
|
function createMsalConfig(config) {
|
|
60
56
|
if (config.msalConfig) {
|
|
61
57
|
return config.msalConfig;
|
|
@@ -65,7 +61,6 @@ function createMsalConfig(config) {
|
|
|
65
61
|
tenantId,
|
|
66
62
|
authorityType = "common",
|
|
67
63
|
redirectUri,
|
|
68
|
-
popupRedirectUri,
|
|
69
64
|
postLogoutRedirectUri,
|
|
70
65
|
cacheLocation = "sessionStorage",
|
|
71
66
|
storeAuthStateInCookie = false,
|
|
@@ -88,9 +83,6 @@ function createMsalConfig(config) {
|
|
|
88
83
|
};
|
|
89
84
|
const defaultRedirectUri = typeof window !== "undefined" ? window.location.origin : "http://localhost:3000";
|
|
90
85
|
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;
|
|
94
86
|
if (allowedRedirectUris && allowedRedirectUris.length > 0) {
|
|
95
87
|
if (!isValidRedirectUri(finalRedirectUri, allowedRedirectUris)) {
|
|
96
88
|
throw new Error(
|
|
@@ -117,10 +109,6 @@ function createMsalConfig(config) {
|
|
|
117
109
|
storeAuthStateInCookie
|
|
118
110
|
},
|
|
119
111
|
system: {
|
|
120
|
-
windowHashTimeout: 6e4,
|
|
121
|
-
// Increase timeout for popup
|
|
122
|
-
iframeHashTimeout: 6e3,
|
|
123
|
-
loadFrameTimeout: 0,
|
|
124
112
|
loggerOptions: {
|
|
125
113
|
loggerCallback: loggerCallback || ((level, message, containsPii) => {
|
|
126
114
|
if (containsPii || !enableLogging) return;
|
|
@@ -159,13 +147,6 @@ function MsalAuthProvider({ children, loadingComponent, onInitialized, ...config
|
|
|
159
147
|
if (typeof window === "undefined") {
|
|
160
148
|
return;
|
|
161
149
|
}
|
|
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
|
-
}
|
|
169
150
|
if (instanceRef.current) {
|
|
170
151
|
return;
|
|
171
152
|
}
|
|
@@ -174,17 +155,16 @@ function MsalAuthProvider({ children, loadingComponent, onInitialized, ...config
|
|
|
174
155
|
const msalConfig = createMsalConfig(config);
|
|
175
156
|
const instance = new PublicClientApplication(msalConfig);
|
|
176
157
|
await instance.initialize();
|
|
177
|
-
const isInPopup3 = window.opener && window.opener !== window;
|
|
178
158
|
try {
|
|
179
159
|
const response = await instance.handleRedirectPromise();
|
|
180
160
|
if (response) {
|
|
181
161
|
if (config.enableLogging) {
|
|
182
|
-
console.log("[MSAL] Redirect authentication successful"
|
|
162
|
+
console.log("[MSAL] Redirect authentication successful");
|
|
183
163
|
}
|
|
184
164
|
if (response.account) {
|
|
185
165
|
instance.setActiveAccount(response.account);
|
|
186
166
|
}
|
|
187
|
-
if (
|
|
167
|
+
if (window.location.hash) {
|
|
188
168
|
window.history.replaceState(null, "", window.location.pathname + window.location.search);
|
|
189
169
|
}
|
|
190
170
|
}
|
|
@@ -200,7 +180,7 @@ function MsalAuthProvider({ children, loadingComponent, onInitialized, ...config
|
|
|
200
180
|
} else {
|
|
201
181
|
console.error("[MSAL] Redirect handling error:", redirectError);
|
|
202
182
|
}
|
|
203
|
-
if (
|
|
183
|
+
if (window.location.hash && (window.location.hash.includes("code=") || window.location.hash.includes("error="))) {
|
|
204
184
|
window.history.replaceState(null, "", window.location.pathname + window.location.search);
|
|
205
185
|
}
|
|
206
186
|
}
|
|
@@ -256,10 +236,6 @@ function MsalAuthProvider({ children, loadingComponent, onInitialized, ...config
|
|
|
256
236
|
if (typeof window === "undefined") {
|
|
257
237
|
return /* @__PURE__ */ jsx(Fragment, { children: loadingComponent || /* @__PURE__ */ jsx("div", { children: "Loading authentication..." }) });
|
|
258
238
|
}
|
|
259
|
-
const isInPopup = window.opener && window.opener !== window;
|
|
260
|
-
if (isInPopup) {
|
|
261
|
-
return null;
|
|
262
|
-
}
|
|
263
239
|
if (!msalInstance) {
|
|
264
240
|
return /* @__PURE__ */ jsx(Fragment, { children: loadingComponent || /* @__PURE__ */ jsx("div", { children: "Loading authentication..." }) });
|
|
265
241
|
}
|
|
@@ -275,42 +251,12 @@ function MSALProvider({ children, ...props }) {
|
|
|
275
251
|
// src/hooks/useMsalAuth.ts
|
|
276
252
|
import { useMsal, useAccount } from "@azure/msal-react";
|
|
277
253
|
import { InteractionStatus } from "@azure/msal-browser";
|
|
278
|
-
import { useCallback, useMemo
|
|
254
|
+
import { useCallback, useMemo } from "react";
|
|
279
255
|
var pendingTokenRequests = /* @__PURE__ */ new Map();
|
|
280
256
|
function useMsalAuth(defaultScopes = ["User.Read"]) {
|
|
281
257
|
const { instance, accounts, inProgress } = useMsal();
|
|
282
258
|
const account = useAccount(accounts[0] || null);
|
|
283
|
-
const popupInProgressRef = useRef2(false);
|
|
284
259
|
const isAuthenticated = useMemo(() => accounts.length > 0, [accounts]);
|
|
285
|
-
const loginPopup = useCallback(
|
|
286
|
-
async (scopes = defaultScopes) => {
|
|
287
|
-
if (inProgress !== InteractionStatus.None) {
|
|
288
|
-
console.warn("[MSAL] Interaction already in progress");
|
|
289
|
-
return;
|
|
290
|
-
}
|
|
291
|
-
try {
|
|
292
|
-
const popupRedirectUri = getPopupRedirectUri();
|
|
293
|
-
const request = {
|
|
294
|
-
scopes,
|
|
295
|
-
prompt: "select_account",
|
|
296
|
-
// Use popup-specific redirect URI (defaults to /blank.html)
|
|
297
|
-
redirectUri: popupRedirectUri
|
|
298
|
-
};
|
|
299
|
-
const response = await instance.loginPopup(request);
|
|
300
|
-
if (response?.account) {
|
|
301
|
-
instance.setActiveAccount(response.account);
|
|
302
|
-
}
|
|
303
|
-
} catch (error) {
|
|
304
|
-
if (error?.errorCode === "user_cancelled") {
|
|
305
|
-
console.log("[MSAL] User cancelled login");
|
|
306
|
-
return;
|
|
307
|
-
}
|
|
308
|
-
console.error("[MSAL] Login popup failed:", error);
|
|
309
|
-
throw error;
|
|
310
|
-
}
|
|
311
|
-
},
|
|
312
|
-
[instance, defaultScopes, inProgress]
|
|
313
|
-
);
|
|
314
260
|
const loginRedirect = useCallback(
|
|
315
261
|
async (scopes = defaultScopes) => {
|
|
316
262
|
if (inProgress !== InteractionStatus.None) {
|
|
@@ -334,16 +280,6 @@ function useMsalAuth(defaultScopes = ["User.Read"]) {
|
|
|
334
280
|
},
|
|
335
281
|
[instance, defaultScopes, inProgress]
|
|
336
282
|
);
|
|
337
|
-
const logoutPopup = useCallback(async () => {
|
|
338
|
-
try {
|
|
339
|
-
await instance.logoutPopup({
|
|
340
|
-
account: account || void 0
|
|
341
|
-
});
|
|
342
|
-
} catch (error) {
|
|
343
|
-
console.error("[MSAL] Logout popup failed:", error);
|
|
344
|
-
throw error;
|
|
345
|
-
}
|
|
346
|
-
}, [instance, account]);
|
|
347
283
|
const logoutRedirect = useCallback(async () => {
|
|
348
284
|
try {
|
|
349
285
|
await instance.logoutRedirect({
|
|
@@ -374,31 +310,6 @@ function useMsalAuth(defaultScopes = ["User.Read"]) {
|
|
|
374
310
|
},
|
|
375
311
|
[instance, account, defaultScopes]
|
|
376
312
|
);
|
|
377
|
-
const acquireTokenPopup = useCallback(
|
|
378
|
-
async (scopes = defaultScopes) => {
|
|
379
|
-
if (!account) {
|
|
380
|
-
throw new Error("[MSAL] No active account. Please login first.");
|
|
381
|
-
}
|
|
382
|
-
if (popupInProgressRef.current) {
|
|
383
|
-
throw new Error("[MSAL] Popup already in progress. Please wait.");
|
|
384
|
-
}
|
|
385
|
-
try {
|
|
386
|
-
popupInProgressRef.current = true;
|
|
387
|
-
const request = {
|
|
388
|
-
scopes,
|
|
389
|
-
account
|
|
390
|
-
};
|
|
391
|
-
const response = await instance.acquireTokenPopup(request);
|
|
392
|
-
return response.accessToken;
|
|
393
|
-
} catch (error) {
|
|
394
|
-
console.error("[MSAL] Token popup acquisition failed:", error);
|
|
395
|
-
throw error;
|
|
396
|
-
} finally {
|
|
397
|
-
popupInProgressRef.current = false;
|
|
398
|
-
}
|
|
399
|
-
},
|
|
400
|
-
[instance, account, defaultScopes]
|
|
401
|
-
);
|
|
402
313
|
const acquireTokenRedirect = useCallback(
|
|
403
314
|
async (scopes = defaultScopes) => {
|
|
404
315
|
if (!account) {
|
|
@@ -428,8 +339,9 @@ function useMsalAuth(defaultScopes = ["User.Read"]) {
|
|
|
428
339
|
try {
|
|
429
340
|
return await acquireTokenSilent(scopes);
|
|
430
341
|
} catch (error) {
|
|
431
|
-
console.warn("[MSAL] Silent token acquisition failed, falling back to
|
|
432
|
-
|
|
342
|
+
console.warn("[MSAL] Silent token acquisition failed, falling back to redirect");
|
|
343
|
+
await acquireTokenRedirect(scopes);
|
|
344
|
+
throw new Error("[MSAL] Redirecting for token acquisition");
|
|
433
345
|
} finally {
|
|
434
346
|
pendingTokenRequests.delete(requestKey);
|
|
435
347
|
}
|
|
@@ -437,7 +349,7 @@ function useMsalAuth(defaultScopes = ["User.Read"]) {
|
|
|
437
349
|
pendingTokenRequests.set(requestKey, tokenRequest);
|
|
438
350
|
return tokenRequest;
|
|
439
351
|
},
|
|
440
|
-
[acquireTokenSilent,
|
|
352
|
+
[acquireTokenSilent, acquireTokenRedirect, defaultScopes, account]
|
|
441
353
|
);
|
|
442
354
|
const clearSession = useCallback(async () => {
|
|
443
355
|
instance.setActiveAccount(null);
|
|
@@ -448,13 +360,10 @@ function useMsalAuth(defaultScopes = ["User.Read"]) {
|
|
|
448
360
|
accounts,
|
|
449
361
|
isAuthenticated,
|
|
450
362
|
inProgress: inProgress !== InteractionStatus.None,
|
|
451
|
-
loginPopup,
|
|
452
363
|
loginRedirect,
|
|
453
|
-
logoutPopup,
|
|
454
364
|
logoutRedirect,
|
|
455
365
|
acquireToken,
|
|
456
366
|
acquireTokenSilent,
|
|
457
|
-
acquireTokenPopup,
|
|
458
367
|
acquireTokenRedirect,
|
|
459
368
|
clearSession
|
|
460
369
|
};
|
|
@@ -467,23 +376,18 @@ function MicrosoftSignInButton({
|
|
|
467
376
|
text = "Sign in with Microsoft",
|
|
468
377
|
variant = "dark",
|
|
469
378
|
size = "medium",
|
|
470
|
-
useRedirect = false,
|
|
471
379
|
scopes,
|
|
472
380
|
className = "",
|
|
473
381
|
style,
|
|
474
382
|
onSuccess,
|
|
475
383
|
onError
|
|
476
384
|
}) {
|
|
477
|
-
const {
|
|
385
|
+
const { loginRedirect, inProgress } = useMsalAuth();
|
|
478
386
|
const [isLoading, setIsLoading] = useState2(false);
|
|
479
387
|
const handleClick = async () => {
|
|
480
388
|
setIsLoading(true);
|
|
481
389
|
try {
|
|
482
|
-
|
|
483
|
-
await loginRedirect(scopes);
|
|
484
|
-
} else {
|
|
485
|
-
await loginPopup(scopes);
|
|
486
|
-
}
|
|
390
|
+
await loginRedirect(scopes);
|
|
487
391
|
onSuccess?.();
|
|
488
392
|
} catch (error) {
|
|
489
393
|
onError?.(error);
|
|
@@ -566,20 +470,15 @@ function SignOutButton({
|
|
|
566
470
|
text = "Sign out",
|
|
567
471
|
variant = "dark",
|
|
568
472
|
size = "medium",
|
|
569
|
-
useRedirect = false,
|
|
570
473
|
className = "",
|
|
571
474
|
style,
|
|
572
475
|
onSuccess,
|
|
573
476
|
onError
|
|
574
477
|
}) {
|
|
575
|
-
const {
|
|
478
|
+
const { logoutRedirect, inProgress } = useMsalAuth();
|
|
576
479
|
const handleClick = async () => {
|
|
577
480
|
try {
|
|
578
|
-
|
|
579
|
-
await logoutRedirect();
|
|
580
|
-
} else {
|
|
581
|
-
await logoutPopup();
|
|
582
|
-
}
|
|
481
|
+
await logoutRedirect();
|
|
583
482
|
onSuccess?.();
|
|
584
483
|
} catch (error) {
|
|
585
484
|
onError?.(error);
|
|
@@ -1064,28 +963,23 @@ function AuthGuard({
|
|
|
1064
963
|
children,
|
|
1065
964
|
loadingComponent,
|
|
1066
965
|
fallbackComponent,
|
|
1067
|
-
useRedirect = true,
|
|
1068
966
|
scopes,
|
|
1069
967
|
onAuthRequired
|
|
1070
968
|
}) {
|
|
1071
|
-
const { isAuthenticated, inProgress, loginRedirect
|
|
969
|
+
const { isAuthenticated, inProgress, loginRedirect } = useMsalAuth();
|
|
1072
970
|
useEffect4(() => {
|
|
1073
971
|
if (!isAuthenticated && !inProgress) {
|
|
1074
972
|
onAuthRequired?.();
|
|
1075
973
|
const login = async () => {
|
|
1076
974
|
try {
|
|
1077
|
-
|
|
1078
|
-
await loginRedirect(scopes);
|
|
1079
|
-
} else {
|
|
1080
|
-
await loginPopup(scopes);
|
|
1081
|
-
}
|
|
975
|
+
await loginRedirect(scopes);
|
|
1082
976
|
} catch (error) {
|
|
1083
977
|
console.error("[AuthGuard] Authentication failed:", error);
|
|
1084
978
|
}
|
|
1085
979
|
};
|
|
1086
980
|
login();
|
|
1087
981
|
}
|
|
1088
|
-
}, [isAuthenticated, inProgress,
|
|
982
|
+
}, [isAuthenticated, inProgress, scopes, loginRedirect, onAuthRequired]);
|
|
1089
983
|
if (inProgress) {
|
|
1090
984
|
return /* @__PURE__ */ jsx7(Fragment3, { children: loadingComponent || /* @__PURE__ */ jsx7("div", { children: "Authenticating..." }) });
|
|
1091
985
|
}
|
|
@@ -1654,7 +1548,6 @@ export {
|
|
|
1654
1548
|
createScopedLogger,
|
|
1655
1549
|
getDebugLogger,
|
|
1656
1550
|
getMsalInstance,
|
|
1657
|
-
getPopupRedirectUri,
|
|
1658
1551
|
isValidAccountData,
|
|
1659
1552
|
isValidRedirectUri,
|
|
1660
1553
|
isValidScope,
|
package/package.json
CHANGED