@chemmangat/msal-next 3.0.3 → 3.0.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/dist/index.d.mts +933 -1
- package/dist/index.d.ts +933 -1
- package/dist/index.js +1687 -1
- package/dist/index.mjs +1633 -0
- package/dist/server.js +115 -1
- package/dist/server.mjs +87 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -1,2 +1,934 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { Configuration, LogLevel, IPublicClientApplication, PublicClientApplication, AccountInfo } from '@azure/msal-browser';
|
|
3
|
+
export { AccountInfo } from '@azure/msal-browser';
|
|
4
|
+
import { ReactNode, CSSProperties, Component, ErrorInfo, ComponentType } from 'react';
|
|
5
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
6
|
+
export { useAccount, useIsAuthenticated, useMsal } from '@azure/msal-react';
|
|
1
7
|
|
|
2
|
-
|
|
8
|
+
/**
|
|
9
|
+
* Custom token claims interface for TypeScript generics
|
|
10
|
+
* Extend this interface to add your custom claims
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```tsx
|
|
14
|
+
* interface MyCustomClaims extends CustomTokenClaims {
|
|
15
|
+
* roles: string[];
|
|
16
|
+
* department: string;
|
|
17
|
+
* }
|
|
18
|
+
*
|
|
19
|
+
* const claims = account.idTokenClaims as MyCustomClaims;
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
interface CustomTokenClaims {
|
|
23
|
+
[key: string]: any;
|
|
24
|
+
}
|
|
25
|
+
interface MsalAuthConfig {
|
|
26
|
+
/**
|
|
27
|
+
* Azure AD Application (client) ID
|
|
28
|
+
*/
|
|
29
|
+
clientId: string;
|
|
30
|
+
/**
|
|
31
|
+
* Azure AD Directory (tenant) ID (optional for multi-tenant)
|
|
32
|
+
*/
|
|
33
|
+
tenantId?: string;
|
|
34
|
+
/**
|
|
35
|
+
* Authority type: 'common' for multi-tenant, 'organizations', 'consumers', or 'tenant' for single-tenant
|
|
36
|
+
* @default 'common'
|
|
37
|
+
*/
|
|
38
|
+
authorityType?: 'common' | 'organizations' | 'consumers' | 'tenant';
|
|
39
|
+
/**
|
|
40
|
+
* Redirect URI after authentication
|
|
41
|
+
* @default window.location.origin
|
|
42
|
+
*/
|
|
43
|
+
redirectUri?: string;
|
|
44
|
+
/**
|
|
45
|
+
* Post logout redirect URI
|
|
46
|
+
* @default redirectUri
|
|
47
|
+
*/
|
|
48
|
+
postLogoutRedirectUri?: string;
|
|
49
|
+
/**
|
|
50
|
+
* Default scopes for authentication
|
|
51
|
+
* @default ['User.Read']
|
|
52
|
+
*/
|
|
53
|
+
scopes?: string[];
|
|
54
|
+
/**
|
|
55
|
+
* Cache location: 'sessionStorage', 'localStorage', or 'memoryStorage'
|
|
56
|
+
* @default 'sessionStorage'
|
|
57
|
+
*/
|
|
58
|
+
cacheLocation?: 'sessionStorage' | 'localStorage' | 'memoryStorage';
|
|
59
|
+
/**
|
|
60
|
+
* Store auth state in cookie (for IE11/Edge legacy)
|
|
61
|
+
* @default false
|
|
62
|
+
*/
|
|
63
|
+
storeAuthStateInCookie?: boolean;
|
|
64
|
+
/**
|
|
65
|
+
* Navigate to login request URL after authentication
|
|
66
|
+
* @default true
|
|
67
|
+
*/
|
|
68
|
+
navigateToLoginRequestUrl?: boolean;
|
|
69
|
+
/**
|
|
70
|
+
* Custom MSAL configuration (overrides all other options)
|
|
71
|
+
*/
|
|
72
|
+
msalConfig?: Configuration;
|
|
73
|
+
/**
|
|
74
|
+
* Enable debug logging
|
|
75
|
+
* @default false
|
|
76
|
+
*/
|
|
77
|
+
enableLogging?: boolean;
|
|
78
|
+
/**
|
|
79
|
+
* Custom logger callback
|
|
80
|
+
*/
|
|
81
|
+
loggerCallback?: (level: LogLevel, message: string, containsPii: boolean) => void;
|
|
82
|
+
/**
|
|
83
|
+
* Allowed redirect URIs for validation (optional but recommended)
|
|
84
|
+
* Helps prevent open redirect vulnerabilities
|
|
85
|
+
* @example ['https://myapp.com', 'http://localhost:3000']
|
|
86
|
+
*/
|
|
87
|
+
allowedRedirectUris?: string[];
|
|
88
|
+
/**
|
|
89
|
+
* Loading component to show while MSAL initializes
|
|
90
|
+
*/
|
|
91
|
+
loadingComponent?: ReactNode;
|
|
92
|
+
/**
|
|
93
|
+
* Callback invoked after MSAL initialization completes successfully
|
|
94
|
+
*/
|
|
95
|
+
onInitialized?: (instance: IPublicClientApplication) => void;
|
|
96
|
+
}
|
|
97
|
+
interface MsalAuthProviderProps extends MsalAuthConfig {
|
|
98
|
+
children: ReactNode;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Get the current MSAL instance
|
|
103
|
+
* @returns The MSAL instance or null if not initialized
|
|
104
|
+
*/
|
|
105
|
+
declare function getMsalInstance(): PublicClientApplication | null;
|
|
106
|
+
declare function MsalAuthProvider({ children, loadingComponent, onInitialized, ...config }: MsalAuthProviderProps): react_jsx_runtime.JSX.Element;
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Pre-configured MSALProvider component for Next.js App Router layouts.
|
|
110
|
+
* This component is already marked as 'use client', so you can use it directly
|
|
111
|
+
* in your server-side layout.tsx without needing to create a separate client component.
|
|
112
|
+
*
|
|
113
|
+
* @example
|
|
114
|
+
* ```tsx
|
|
115
|
+
* // app/layout.tsx
|
|
116
|
+
* import { MSALProvider } from '@chemmangat/msal-next'
|
|
117
|
+
*
|
|
118
|
+
* export default function RootLayout({ children }) {
|
|
119
|
+
* return (
|
|
120
|
+
* <html lang="en">
|
|
121
|
+
* <body>
|
|
122
|
+
* <MSALProvider
|
|
123
|
+
* clientId={process.env.NEXT_PUBLIC_AZURE_AD_CLIENT_ID!}
|
|
124
|
+
* tenantId={process.env.NEXT_PUBLIC_AZURE_AD_TENANT_ID!}
|
|
125
|
+
* >
|
|
126
|
+
* {children}
|
|
127
|
+
* </MSALProvider>
|
|
128
|
+
* </body>
|
|
129
|
+
* </html>
|
|
130
|
+
* )
|
|
131
|
+
* }
|
|
132
|
+
* ```
|
|
133
|
+
*/
|
|
134
|
+
declare function MSALProvider({ children, ...props }: MsalAuthProviderProps): react_jsx_runtime.JSX.Element;
|
|
135
|
+
|
|
136
|
+
interface MicrosoftSignInButtonProps {
|
|
137
|
+
/**
|
|
138
|
+
* Button text
|
|
139
|
+
* @default 'Sign in with Microsoft'
|
|
140
|
+
*/
|
|
141
|
+
text?: string;
|
|
142
|
+
/**
|
|
143
|
+
* Button variant
|
|
144
|
+
* @default 'dark'
|
|
145
|
+
*/
|
|
146
|
+
variant?: 'dark' | 'light';
|
|
147
|
+
/**
|
|
148
|
+
* Button size
|
|
149
|
+
* @default 'medium'
|
|
150
|
+
*/
|
|
151
|
+
size?: 'small' | 'medium' | 'large';
|
|
152
|
+
/**
|
|
153
|
+
* Use redirect flow instead of popup
|
|
154
|
+
* @default false
|
|
155
|
+
*/
|
|
156
|
+
useRedirect?: boolean;
|
|
157
|
+
/**
|
|
158
|
+
* Scopes to request
|
|
159
|
+
*/
|
|
160
|
+
scopes?: string[];
|
|
161
|
+
/**
|
|
162
|
+
* Custom className
|
|
163
|
+
*/
|
|
164
|
+
className?: string;
|
|
165
|
+
/**
|
|
166
|
+
* Custom styles
|
|
167
|
+
*/
|
|
168
|
+
style?: CSSProperties;
|
|
169
|
+
/**
|
|
170
|
+
* Callback on successful login
|
|
171
|
+
*/
|
|
172
|
+
onSuccess?: () => void;
|
|
173
|
+
/**
|
|
174
|
+
* Callback on error
|
|
175
|
+
*/
|
|
176
|
+
onError?: (error: Error) => void;
|
|
177
|
+
}
|
|
178
|
+
declare function MicrosoftSignInButton({ text, variant, size, useRedirect, scopes, className, style, onSuccess, onError, }: MicrosoftSignInButtonProps): react_jsx_runtime.JSX.Element;
|
|
179
|
+
|
|
180
|
+
interface SignOutButtonProps {
|
|
181
|
+
/**
|
|
182
|
+
* Button text
|
|
183
|
+
* @default 'Sign out'
|
|
184
|
+
*/
|
|
185
|
+
text?: string;
|
|
186
|
+
/**
|
|
187
|
+
* Button variant
|
|
188
|
+
* @default 'dark'
|
|
189
|
+
*/
|
|
190
|
+
variant?: 'dark' | 'light';
|
|
191
|
+
/**
|
|
192
|
+
* Button size
|
|
193
|
+
* @default 'medium'
|
|
194
|
+
*/
|
|
195
|
+
size?: 'small' | 'medium' | 'large';
|
|
196
|
+
/**
|
|
197
|
+
* Use redirect flow instead of popup
|
|
198
|
+
* @default false
|
|
199
|
+
*/
|
|
200
|
+
useRedirect?: boolean;
|
|
201
|
+
/**
|
|
202
|
+
* Custom className
|
|
203
|
+
*/
|
|
204
|
+
className?: string;
|
|
205
|
+
/**
|
|
206
|
+
* Custom styles
|
|
207
|
+
*/
|
|
208
|
+
style?: CSSProperties;
|
|
209
|
+
/**
|
|
210
|
+
* Callback on successful logout
|
|
211
|
+
*/
|
|
212
|
+
onSuccess?: () => void;
|
|
213
|
+
/**
|
|
214
|
+
* Callback on error
|
|
215
|
+
*/
|
|
216
|
+
onError?: (error: Error) => void;
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* SignOutButton component with Microsoft branding
|
|
220
|
+
*
|
|
221
|
+
* @example
|
|
222
|
+
* ```tsx
|
|
223
|
+
* <SignOutButton variant="light" />
|
|
224
|
+
* ```
|
|
225
|
+
*/
|
|
226
|
+
declare function SignOutButton({ text, variant, size, useRedirect, className, style, onSuccess, onError, }: SignOutButtonProps): react_jsx_runtime.JSX.Element;
|
|
227
|
+
|
|
228
|
+
interface UserAvatarProps {
|
|
229
|
+
/**
|
|
230
|
+
* Avatar size in pixels
|
|
231
|
+
* @default 40
|
|
232
|
+
*/
|
|
233
|
+
size?: number;
|
|
234
|
+
/**
|
|
235
|
+
* Custom className
|
|
236
|
+
*/
|
|
237
|
+
className?: string;
|
|
238
|
+
/**
|
|
239
|
+
* Custom styles
|
|
240
|
+
*/
|
|
241
|
+
style?: CSSProperties;
|
|
242
|
+
/**
|
|
243
|
+
* Show user name tooltip on hover
|
|
244
|
+
* @default true
|
|
245
|
+
*/
|
|
246
|
+
showTooltip?: boolean;
|
|
247
|
+
/**
|
|
248
|
+
* Fallback image URL if MS Graph photo fails
|
|
249
|
+
*/
|
|
250
|
+
fallbackImage?: string;
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* UserAvatar component that displays user photo from MS Graph with fallback initials
|
|
254
|
+
*
|
|
255
|
+
* @example
|
|
256
|
+
* ```tsx
|
|
257
|
+
* <UserAvatar size={48} />
|
|
258
|
+
* ```
|
|
259
|
+
*/
|
|
260
|
+
declare function UserAvatar({ size, className, style, showTooltip, fallbackImage, }: UserAvatarProps): react_jsx_runtime.JSX.Element;
|
|
261
|
+
|
|
262
|
+
interface AuthStatusProps {
|
|
263
|
+
/**
|
|
264
|
+
* Custom className
|
|
265
|
+
*/
|
|
266
|
+
className?: string;
|
|
267
|
+
/**
|
|
268
|
+
* Custom styles
|
|
269
|
+
*/
|
|
270
|
+
style?: CSSProperties;
|
|
271
|
+
/**
|
|
272
|
+
* Show detailed status (includes username)
|
|
273
|
+
* @default false
|
|
274
|
+
*/
|
|
275
|
+
showDetails?: boolean;
|
|
276
|
+
/**
|
|
277
|
+
* Custom render function for loading state
|
|
278
|
+
*/
|
|
279
|
+
renderLoading?: () => ReactNode;
|
|
280
|
+
/**
|
|
281
|
+
* Custom render function for authenticated state
|
|
282
|
+
*/
|
|
283
|
+
renderAuthenticated?: (username: string) => ReactNode;
|
|
284
|
+
/**
|
|
285
|
+
* Custom render function for unauthenticated state
|
|
286
|
+
*/
|
|
287
|
+
renderUnauthenticated?: () => ReactNode;
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* AuthStatus component that shows current authentication state
|
|
291
|
+
*
|
|
292
|
+
* @example
|
|
293
|
+
* ```tsx
|
|
294
|
+
* <AuthStatus showDetails />
|
|
295
|
+
* ```
|
|
296
|
+
*/
|
|
297
|
+
declare function AuthStatus({ className, style, showDetails, renderLoading, renderAuthenticated, renderUnauthenticated, }: AuthStatusProps): react_jsx_runtime.JSX.Element;
|
|
298
|
+
|
|
299
|
+
interface AuthGuardProps {
|
|
300
|
+
/**
|
|
301
|
+
* Content to render when authenticated
|
|
302
|
+
*/
|
|
303
|
+
children: ReactNode;
|
|
304
|
+
/**
|
|
305
|
+
* Component to show while checking authentication
|
|
306
|
+
*/
|
|
307
|
+
loadingComponent?: ReactNode;
|
|
308
|
+
/**
|
|
309
|
+
* Component to show when not authenticated (before redirect)
|
|
310
|
+
*/
|
|
311
|
+
fallbackComponent?: ReactNode;
|
|
312
|
+
/**
|
|
313
|
+
* Use redirect flow instead of popup
|
|
314
|
+
* @default true
|
|
315
|
+
*/
|
|
316
|
+
useRedirect?: boolean;
|
|
317
|
+
/**
|
|
318
|
+
* Scopes to request during authentication
|
|
319
|
+
*/
|
|
320
|
+
scopes?: string[];
|
|
321
|
+
/**
|
|
322
|
+
* Callback when authentication is required
|
|
323
|
+
*/
|
|
324
|
+
onAuthRequired?: () => void;
|
|
325
|
+
}
|
|
326
|
+
/**
|
|
327
|
+
* AuthGuard component that protects content and auto-redirects to login
|
|
328
|
+
*
|
|
329
|
+
* @example
|
|
330
|
+
* ```tsx
|
|
331
|
+
* <AuthGuard>
|
|
332
|
+
* <ProtectedContent />
|
|
333
|
+
* </AuthGuard>
|
|
334
|
+
* ```
|
|
335
|
+
*/
|
|
336
|
+
declare function AuthGuard({ children, loadingComponent, fallbackComponent, useRedirect, scopes, onAuthRequired, }: AuthGuardProps): react_jsx_runtime.JSX.Element;
|
|
337
|
+
|
|
338
|
+
interface ErrorBoundaryProps {
|
|
339
|
+
/**
|
|
340
|
+
* Content to render when no error
|
|
341
|
+
*/
|
|
342
|
+
children: ReactNode;
|
|
343
|
+
/**
|
|
344
|
+
* Custom error fallback component
|
|
345
|
+
*/
|
|
346
|
+
fallback?: (error: Error, reset: () => void) => ReactNode;
|
|
347
|
+
/**
|
|
348
|
+
* Callback when error occurs
|
|
349
|
+
*/
|
|
350
|
+
onError?: (error: Error, errorInfo: ErrorInfo) => void;
|
|
351
|
+
/**
|
|
352
|
+
* Enable debug logging
|
|
353
|
+
* @default false
|
|
354
|
+
*/
|
|
355
|
+
debug?: boolean;
|
|
356
|
+
}
|
|
357
|
+
interface ErrorBoundaryState {
|
|
358
|
+
hasError: boolean;
|
|
359
|
+
error: Error | null;
|
|
360
|
+
}
|
|
361
|
+
/**
|
|
362
|
+
* Error boundary for catching authentication errors
|
|
363
|
+
*
|
|
364
|
+
* @example
|
|
365
|
+
* ```tsx
|
|
366
|
+
* <ErrorBoundary>
|
|
367
|
+
* <MsalAuthProvider clientId="...">
|
|
368
|
+
* <App />
|
|
369
|
+
* </MsalAuthProvider>
|
|
370
|
+
* </ErrorBoundary>
|
|
371
|
+
* ```
|
|
372
|
+
*/
|
|
373
|
+
declare class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {
|
|
374
|
+
constructor(props: ErrorBoundaryProps);
|
|
375
|
+
static getDerivedStateFromError(error: Error): ErrorBoundaryState;
|
|
376
|
+
componentDidCatch(error: Error, errorInfo: ErrorInfo): void;
|
|
377
|
+
reset: () => void;
|
|
378
|
+
render(): ReactNode;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
interface UseMsalAuthReturn {
|
|
382
|
+
/**
|
|
383
|
+
* Current authenticated account
|
|
384
|
+
*/
|
|
385
|
+
account: AccountInfo | null;
|
|
386
|
+
/**
|
|
387
|
+
* All accounts in the cache
|
|
388
|
+
*/
|
|
389
|
+
accounts: AccountInfo[];
|
|
390
|
+
/**
|
|
391
|
+
* Whether user is authenticated
|
|
392
|
+
*/
|
|
393
|
+
isAuthenticated: boolean;
|
|
394
|
+
/**
|
|
395
|
+
* Whether MSAL is currently performing an interaction
|
|
396
|
+
*/
|
|
397
|
+
inProgress: boolean;
|
|
398
|
+
/**
|
|
399
|
+
* Login using popup
|
|
400
|
+
*/
|
|
401
|
+
loginPopup: (scopes?: string[]) => Promise<void>;
|
|
402
|
+
/**
|
|
403
|
+
* Login using redirect
|
|
404
|
+
*/
|
|
405
|
+
loginRedirect: (scopes?: string[]) => Promise<void>;
|
|
406
|
+
/**
|
|
407
|
+
* Logout using popup
|
|
408
|
+
*/
|
|
409
|
+
logoutPopup: () => Promise<void>;
|
|
410
|
+
/**
|
|
411
|
+
* Logout using redirect
|
|
412
|
+
*/
|
|
413
|
+
logoutRedirect: () => Promise<void>;
|
|
414
|
+
/**
|
|
415
|
+
* Acquire access token silently (with fallback to popup)
|
|
416
|
+
*/
|
|
417
|
+
acquireToken: (scopes: string[]) => Promise<string>;
|
|
418
|
+
/**
|
|
419
|
+
* Acquire access token silently only (no fallback)
|
|
420
|
+
*/
|
|
421
|
+
acquireTokenSilent: (scopes: string[]) => Promise<string>;
|
|
422
|
+
/**
|
|
423
|
+
* Acquire access token using popup
|
|
424
|
+
*/
|
|
425
|
+
acquireTokenPopup: (scopes: string[]) => Promise<string>;
|
|
426
|
+
/**
|
|
427
|
+
* Acquire access token using redirect
|
|
428
|
+
*/
|
|
429
|
+
acquireTokenRedirect: (scopes: string[]) => Promise<void>;
|
|
430
|
+
/**
|
|
431
|
+
* Clear MSAL session without triggering Microsoft logout
|
|
432
|
+
*/
|
|
433
|
+
clearSession: () => Promise<void>;
|
|
434
|
+
}
|
|
435
|
+
declare function useMsalAuth(defaultScopes?: string[]): UseMsalAuthReturn;
|
|
436
|
+
|
|
437
|
+
interface GraphApiOptions extends RequestInit {
|
|
438
|
+
/**
|
|
439
|
+
* Scopes required for the API call
|
|
440
|
+
* @default ['User.Read']
|
|
441
|
+
*/
|
|
442
|
+
scopes?: string[];
|
|
443
|
+
/**
|
|
444
|
+
* API version
|
|
445
|
+
* @default 'v1.0'
|
|
446
|
+
*/
|
|
447
|
+
version?: 'v1.0' | 'beta';
|
|
448
|
+
/**
|
|
449
|
+
* Enable debug logging
|
|
450
|
+
* @default false
|
|
451
|
+
*/
|
|
452
|
+
debug?: boolean;
|
|
453
|
+
}
|
|
454
|
+
interface UseGraphApiReturn {
|
|
455
|
+
/**
|
|
456
|
+
* Make a GET request to MS Graph API
|
|
457
|
+
*/
|
|
458
|
+
get: <T = any>(endpoint: string, options?: GraphApiOptions) => Promise<T>;
|
|
459
|
+
/**
|
|
460
|
+
* Make a POST request to MS Graph API
|
|
461
|
+
*/
|
|
462
|
+
post: <T = any>(endpoint: string, body?: any, options?: GraphApiOptions) => Promise<T>;
|
|
463
|
+
/**
|
|
464
|
+
* Make a PUT request to MS Graph API
|
|
465
|
+
*/
|
|
466
|
+
put: <T = any>(endpoint: string, body?: any, options?: GraphApiOptions) => Promise<T>;
|
|
467
|
+
/**
|
|
468
|
+
* Make a PATCH request to MS Graph API
|
|
469
|
+
*/
|
|
470
|
+
patch: <T = any>(endpoint: string, body?: any, options?: GraphApiOptions) => Promise<T>;
|
|
471
|
+
/**
|
|
472
|
+
* Make a DELETE request to MS Graph API
|
|
473
|
+
*/
|
|
474
|
+
delete: <T = any>(endpoint: string, options?: GraphApiOptions) => Promise<T>;
|
|
475
|
+
/**
|
|
476
|
+
* Make a custom request to MS Graph API
|
|
477
|
+
*/
|
|
478
|
+
request: <T = any>(endpoint: string, options?: GraphApiOptions) => Promise<T>;
|
|
479
|
+
}
|
|
480
|
+
/**
|
|
481
|
+
* Hook for making authenticated requests to MS Graph API
|
|
482
|
+
*
|
|
483
|
+
* @example
|
|
484
|
+
* ```tsx
|
|
485
|
+
* const graph = useGraphApi();
|
|
486
|
+
* const user = await graph.get('/me');
|
|
487
|
+
* ```
|
|
488
|
+
*/
|
|
489
|
+
declare function useGraphApi(): UseGraphApiReturn;
|
|
490
|
+
|
|
491
|
+
interface UserProfile {
|
|
492
|
+
id: string;
|
|
493
|
+
displayName: string;
|
|
494
|
+
givenName: string;
|
|
495
|
+
surname: string;
|
|
496
|
+
userPrincipalName: string;
|
|
497
|
+
mail: string;
|
|
498
|
+
jobTitle?: string;
|
|
499
|
+
officeLocation?: string;
|
|
500
|
+
mobilePhone?: string;
|
|
501
|
+
businessPhones?: string[];
|
|
502
|
+
photo?: string;
|
|
503
|
+
}
|
|
504
|
+
interface UseUserProfileReturn {
|
|
505
|
+
/**
|
|
506
|
+
* User profile data
|
|
507
|
+
*/
|
|
508
|
+
profile: UserProfile | null;
|
|
509
|
+
/**
|
|
510
|
+
* Whether profile is loading
|
|
511
|
+
*/
|
|
512
|
+
loading: boolean;
|
|
513
|
+
/**
|
|
514
|
+
* Error if profile fetch failed
|
|
515
|
+
*/
|
|
516
|
+
error: Error | null;
|
|
517
|
+
/**
|
|
518
|
+
* Refetch user profile
|
|
519
|
+
*/
|
|
520
|
+
refetch: () => Promise<void>;
|
|
521
|
+
/**
|
|
522
|
+
* Clear cached profile
|
|
523
|
+
*/
|
|
524
|
+
clearCache: () => void;
|
|
525
|
+
}
|
|
526
|
+
/**
|
|
527
|
+
* Hook for fetching and caching user profile from MS Graph
|
|
528
|
+
*
|
|
529
|
+
* @example
|
|
530
|
+
* ```tsx
|
|
531
|
+
* const { profile, loading } = useUserProfile();
|
|
532
|
+
* ```
|
|
533
|
+
*/
|
|
534
|
+
declare function useUserProfile(): UseUserProfileReturn;
|
|
535
|
+
|
|
536
|
+
interface UseRolesReturn {
|
|
537
|
+
/**
|
|
538
|
+
* User's Azure AD roles
|
|
539
|
+
*/
|
|
540
|
+
roles: string[];
|
|
541
|
+
/**
|
|
542
|
+
* User's Azure AD groups
|
|
543
|
+
*/
|
|
544
|
+
groups: string[];
|
|
545
|
+
/**
|
|
546
|
+
* Whether roles/groups are loading
|
|
547
|
+
*/
|
|
548
|
+
loading: boolean;
|
|
549
|
+
/**
|
|
550
|
+
* Error if fetch failed
|
|
551
|
+
*/
|
|
552
|
+
error: Error | null;
|
|
553
|
+
/**
|
|
554
|
+
* Check if user has a specific role
|
|
555
|
+
*/
|
|
556
|
+
hasRole: (role: string) => boolean;
|
|
557
|
+
/**
|
|
558
|
+
* Check if user is in a specific group
|
|
559
|
+
*/
|
|
560
|
+
hasGroup: (groupId: string) => boolean;
|
|
561
|
+
/**
|
|
562
|
+
* Check if user has any of the specified roles
|
|
563
|
+
*/
|
|
564
|
+
hasAnyRole: (roles: string[]) => boolean;
|
|
565
|
+
/**
|
|
566
|
+
* Check if user has all of the specified roles
|
|
567
|
+
*/
|
|
568
|
+
hasAllRoles: (roles: string[]) => boolean;
|
|
569
|
+
/**
|
|
570
|
+
* Refetch roles and groups
|
|
571
|
+
*/
|
|
572
|
+
refetch: () => Promise<void>;
|
|
573
|
+
}
|
|
574
|
+
/**
|
|
575
|
+
* Hook for fetching user's Azure AD roles and groups
|
|
576
|
+
*
|
|
577
|
+
* @example
|
|
578
|
+
* ```tsx
|
|
579
|
+
* const { roles, hasRole } = useRoles();
|
|
580
|
+
* if (hasRole('Admin')) {
|
|
581
|
+
* // Show admin content
|
|
582
|
+
* }
|
|
583
|
+
* ```
|
|
584
|
+
*/
|
|
585
|
+
declare function useRoles(): UseRolesReturn;
|
|
586
|
+
|
|
587
|
+
declare function createMsalConfig(config: MsalAuthConfig): Configuration;
|
|
588
|
+
|
|
589
|
+
interface WithAuthOptions extends Omit<AuthGuardProps, 'children'> {
|
|
590
|
+
/**
|
|
591
|
+
* Display name for the wrapped component (for debugging)
|
|
592
|
+
*/
|
|
593
|
+
displayName?: string;
|
|
594
|
+
}
|
|
595
|
+
/**
|
|
596
|
+
* Higher-order component for protecting pages/components
|
|
597
|
+
*
|
|
598
|
+
* @example
|
|
599
|
+
* ```tsx
|
|
600
|
+
* const ProtectedPage = withAuth(MyPage);
|
|
601
|
+
*
|
|
602
|
+
* // With options
|
|
603
|
+
* const ProtectedPage = withAuth(MyPage, {
|
|
604
|
+
* useRedirect: true,
|
|
605
|
+
* scopes: ['User.Read', 'Mail.Read']
|
|
606
|
+
* });
|
|
607
|
+
* ```
|
|
608
|
+
*/
|
|
609
|
+
declare function withAuth<P extends object>(Component: ComponentType<P>, options?: WithAuthOptions): ComponentType<P>;
|
|
610
|
+
|
|
611
|
+
/**
|
|
612
|
+
* Retry configuration for token acquisition
|
|
613
|
+
*/
|
|
614
|
+
interface RetryConfig {
|
|
615
|
+
/**
|
|
616
|
+
* Maximum number of retry attempts
|
|
617
|
+
* @default 3
|
|
618
|
+
*/
|
|
619
|
+
maxRetries?: number;
|
|
620
|
+
/**
|
|
621
|
+
* Initial delay in milliseconds
|
|
622
|
+
* @default 1000
|
|
623
|
+
*/
|
|
624
|
+
initialDelay?: number;
|
|
625
|
+
/**
|
|
626
|
+
* Maximum delay in milliseconds
|
|
627
|
+
* @default 10000
|
|
628
|
+
*/
|
|
629
|
+
maxDelay?: number;
|
|
630
|
+
/**
|
|
631
|
+
* Backoff multiplier
|
|
632
|
+
* @default 2
|
|
633
|
+
*/
|
|
634
|
+
backoffMultiplier?: number;
|
|
635
|
+
/**
|
|
636
|
+
* Enable debug logging
|
|
637
|
+
* @default false
|
|
638
|
+
*/
|
|
639
|
+
debug?: boolean;
|
|
640
|
+
}
|
|
641
|
+
/**
|
|
642
|
+
* Exponential backoff retry utility for token acquisition
|
|
643
|
+
*
|
|
644
|
+
* @example
|
|
645
|
+
* ```tsx
|
|
646
|
+
* const token = await retryWithBackoff(
|
|
647
|
+
* () => acquireTokenSilent(scopes),
|
|
648
|
+
* { maxRetries: 3, debug: true }
|
|
649
|
+
* );
|
|
650
|
+
* ```
|
|
651
|
+
*/
|
|
652
|
+
declare function retryWithBackoff<T>(fn: () => Promise<T>, config?: RetryConfig): Promise<T>;
|
|
653
|
+
/**
|
|
654
|
+
* Create a retry wrapper for a function
|
|
655
|
+
*
|
|
656
|
+
* @example
|
|
657
|
+
* ```tsx
|
|
658
|
+
* const acquireTokenWithRetry = createRetryWrapper(acquireToken, {
|
|
659
|
+
* maxRetries: 3,
|
|
660
|
+
* debug: true
|
|
661
|
+
* });
|
|
662
|
+
*
|
|
663
|
+
* const token = await acquireTokenWithRetry(scopes);
|
|
664
|
+
* ```
|
|
665
|
+
*/
|
|
666
|
+
declare function createRetryWrapper<TArgs extends any[], TReturn>(fn: (...args: TArgs) => Promise<TReturn>, config?: RetryConfig): (...args: TArgs) => Promise<TReturn>;
|
|
667
|
+
|
|
668
|
+
/**
|
|
669
|
+
* Debug logger configuration
|
|
670
|
+
*/
|
|
671
|
+
interface DebugLoggerConfig {
|
|
672
|
+
/**
|
|
673
|
+
* Enable debug mode
|
|
674
|
+
* @default false
|
|
675
|
+
*/
|
|
676
|
+
enabled?: boolean;
|
|
677
|
+
/**
|
|
678
|
+
* Prefix for log messages
|
|
679
|
+
* @default '[MSAL-Next]'
|
|
680
|
+
*/
|
|
681
|
+
prefix?: string;
|
|
682
|
+
/**
|
|
683
|
+
* Show timestamps
|
|
684
|
+
* @default true
|
|
685
|
+
*/
|
|
686
|
+
showTimestamp?: boolean;
|
|
687
|
+
/**
|
|
688
|
+
* Log level
|
|
689
|
+
* @default 'info'
|
|
690
|
+
*/
|
|
691
|
+
level?: 'error' | 'warn' | 'info' | 'debug';
|
|
692
|
+
/**
|
|
693
|
+
* Enable performance tracking
|
|
694
|
+
* @default false
|
|
695
|
+
*/
|
|
696
|
+
enablePerformance?: boolean;
|
|
697
|
+
/**
|
|
698
|
+
* Enable network request logging
|
|
699
|
+
* @default false
|
|
700
|
+
*/
|
|
701
|
+
enableNetworkLogs?: boolean;
|
|
702
|
+
/**
|
|
703
|
+
* Maximum log history size
|
|
704
|
+
* @default 100
|
|
705
|
+
*/
|
|
706
|
+
maxHistorySize?: number;
|
|
707
|
+
}
|
|
708
|
+
/**
|
|
709
|
+
* Log entry for history tracking
|
|
710
|
+
*/
|
|
711
|
+
interface LogEntry {
|
|
712
|
+
timestamp: number;
|
|
713
|
+
level: string;
|
|
714
|
+
message: string;
|
|
715
|
+
data?: any;
|
|
716
|
+
}
|
|
717
|
+
/**
|
|
718
|
+
* Performance timing entry
|
|
719
|
+
*/
|
|
720
|
+
interface PerformanceTiming {
|
|
721
|
+
operation: string;
|
|
722
|
+
startTime: number;
|
|
723
|
+
endTime?: number;
|
|
724
|
+
duration?: number;
|
|
725
|
+
}
|
|
726
|
+
declare class DebugLogger {
|
|
727
|
+
private config;
|
|
728
|
+
private logHistory;
|
|
729
|
+
private performanceTimings;
|
|
730
|
+
constructor(config?: DebugLoggerConfig);
|
|
731
|
+
private shouldLog;
|
|
732
|
+
private formatMessage;
|
|
733
|
+
private addToHistory;
|
|
734
|
+
error(message: string, data?: any): void;
|
|
735
|
+
warn(message: string, data?: any): void;
|
|
736
|
+
info(message: string, data?: any): void;
|
|
737
|
+
debug(message: string, data?: any): void;
|
|
738
|
+
group(label: string): void;
|
|
739
|
+
groupEnd(): void;
|
|
740
|
+
/**
|
|
741
|
+
* Start performance timing for an operation
|
|
742
|
+
*/
|
|
743
|
+
startTiming(operation: string): void;
|
|
744
|
+
/**
|
|
745
|
+
* End performance timing for an operation
|
|
746
|
+
*/
|
|
747
|
+
endTiming(operation: string): number | undefined;
|
|
748
|
+
/**
|
|
749
|
+
* Log network request
|
|
750
|
+
*/
|
|
751
|
+
logRequest(method: string, url: string, options?: any): void;
|
|
752
|
+
/**
|
|
753
|
+
* Log network response
|
|
754
|
+
*/
|
|
755
|
+
logResponse(method: string, url: string, status: number, data?: any): void;
|
|
756
|
+
/**
|
|
757
|
+
* Get log history
|
|
758
|
+
*/
|
|
759
|
+
getHistory(): LogEntry[];
|
|
760
|
+
/**
|
|
761
|
+
* Get performance timings
|
|
762
|
+
*/
|
|
763
|
+
getPerformanceTimings(): PerformanceTiming[];
|
|
764
|
+
/**
|
|
765
|
+
* Clear log history
|
|
766
|
+
*/
|
|
767
|
+
clearHistory(): void;
|
|
768
|
+
/**
|
|
769
|
+
* Clear performance timings
|
|
770
|
+
*/
|
|
771
|
+
clearTimings(): void;
|
|
772
|
+
/**
|
|
773
|
+
* Export logs as JSON
|
|
774
|
+
*/
|
|
775
|
+
exportLogs(): string;
|
|
776
|
+
/**
|
|
777
|
+
* Download logs as a file
|
|
778
|
+
*/
|
|
779
|
+
downloadLogs(filename?: string): void;
|
|
780
|
+
setEnabled(enabled: boolean): void;
|
|
781
|
+
setLevel(level: DebugLoggerConfig['level']): void;
|
|
782
|
+
}
|
|
783
|
+
/**
|
|
784
|
+
* Get or create the global debug logger
|
|
785
|
+
*
|
|
786
|
+
* @example
|
|
787
|
+
* ```tsx
|
|
788
|
+
* const logger = getDebugLogger({
|
|
789
|
+
* enabled: true,
|
|
790
|
+
* level: 'debug',
|
|
791
|
+
* enablePerformance: true,
|
|
792
|
+
* enableNetworkLogs: true
|
|
793
|
+
* });
|
|
794
|
+
*
|
|
795
|
+
* logger.startTiming('token-acquisition');
|
|
796
|
+
* // ... do work
|
|
797
|
+
* logger.endTiming('token-acquisition');
|
|
798
|
+
*
|
|
799
|
+
* logger.logRequest('GET', '/me');
|
|
800
|
+
* logger.info('User logged in', { username: 'user@example.com' });
|
|
801
|
+
*
|
|
802
|
+
* // Export logs for debugging
|
|
803
|
+
* logger.downloadLogs();
|
|
804
|
+
* ```
|
|
805
|
+
*/
|
|
806
|
+
declare function getDebugLogger(config?: DebugLoggerConfig): DebugLogger;
|
|
807
|
+
/**
|
|
808
|
+
* Create a scoped logger with a custom prefix
|
|
809
|
+
*
|
|
810
|
+
* @example
|
|
811
|
+
* ```tsx
|
|
812
|
+
* const logger = createScopedLogger('GraphAPI', {
|
|
813
|
+
* enabled: true,
|
|
814
|
+
* enableNetworkLogs: true
|
|
815
|
+
* });
|
|
816
|
+
* logger.info('Fetching user profile');
|
|
817
|
+
* ```
|
|
818
|
+
*/
|
|
819
|
+
declare function createScopedLogger(scope: string, config?: DebugLoggerConfig): DebugLogger;
|
|
820
|
+
|
|
821
|
+
/**
|
|
822
|
+
* Security utilities for input validation and sanitization
|
|
823
|
+
*/
|
|
824
|
+
/**
|
|
825
|
+
* Validate account data structure from cookie
|
|
826
|
+
*/
|
|
827
|
+
interface ValidatedAccountData {
|
|
828
|
+
homeAccountId: string;
|
|
829
|
+
username: string;
|
|
830
|
+
name?: string;
|
|
831
|
+
}
|
|
832
|
+
/**
|
|
833
|
+
* Safely parse and validate JSON from untrusted sources
|
|
834
|
+
*/
|
|
835
|
+
declare function safeJsonParse<T>(jsonString: string, validator: (data: any) => data is T): T | null;
|
|
836
|
+
/**
|
|
837
|
+
* Validate account data structure
|
|
838
|
+
*/
|
|
839
|
+
declare function isValidAccountData(data: any): data is ValidatedAccountData;
|
|
840
|
+
/**
|
|
841
|
+
* Sanitize error messages to prevent information disclosure
|
|
842
|
+
*/
|
|
843
|
+
declare function sanitizeError(error: unknown): string;
|
|
844
|
+
/**
|
|
845
|
+
* Validate redirect URI to prevent open redirect vulnerabilities
|
|
846
|
+
*/
|
|
847
|
+
declare function isValidRedirectUri(uri: string, allowedOrigins: string[]): boolean;
|
|
848
|
+
/**
|
|
849
|
+
* Validate scope strings to prevent injection
|
|
850
|
+
*/
|
|
851
|
+
declare function isValidScope(scope: string): boolean;
|
|
852
|
+
/**
|
|
853
|
+
* Validate array of scopes
|
|
854
|
+
*/
|
|
855
|
+
declare function validateScopes(scopes: string[]): boolean;
|
|
856
|
+
|
|
857
|
+
interface AuthMiddlewareConfig {
|
|
858
|
+
/**
|
|
859
|
+
* Routes that require authentication
|
|
860
|
+
* @example ['/dashboard', '/profile', '/api/protected']
|
|
861
|
+
*/
|
|
862
|
+
protectedRoutes?: string[];
|
|
863
|
+
/**
|
|
864
|
+
* Routes that should be accessible only when NOT authenticated
|
|
865
|
+
* @example ['/login', '/signup']
|
|
866
|
+
*/
|
|
867
|
+
publicOnlyRoutes?: string[];
|
|
868
|
+
/**
|
|
869
|
+
* Login page path
|
|
870
|
+
* @default '/login'
|
|
871
|
+
*/
|
|
872
|
+
loginPath?: string;
|
|
873
|
+
/**
|
|
874
|
+
* Redirect path after login
|
|
875
|
+
* @default '/'
|
|
876
|
+
*/
|
|
877
|
+
redirectAfterLogin?: string;
|
|
878
|
+
/**
|
|
879
|
+
* Cookie name for session
|
|
880
|
+
* @default 'msal.account'
|
|
881
|
+
*/
|
|
882
|
+
sessionCookie?: string;
|
|
883
|
+
/**
|
|
884
|
+
* Custom authentication check function
|
|
885
|
+
*/
|
|
886
|
+
isAuthenticated?: (request: NextRequest) => boolean | Promise<boolean>;
|
|
887
|
+
/**
|
|
888
|
+
* Enable debug logging
|
|
889
|
+
* @default false
|
|
890
|
+
*/
|
|
891
|
+
debug?: boolean;
|
|
892
|
+
}
|
|
893
|
+
/**
|
|
894
|
+
* Creates authentication middleware for Next.js App Router
|
|
895
|
+
*
|
|
896
|
+
* @example
|
|
897
|
+
* ```tsx
|
|
898
|
+
* // middleware.ts
|
|
899
|
+
* import { createAuthMiddleware } from '@chemmangat/msal-next';
|
|
900
|
+
*
|
|
901
|
+
* export const middleware = createAuthMiddleware({
|
|
902
|
+
* protectedRoutes: ['/dashboard', '/profile'],
|
|
903
|
+
* publicOnlyRoutes: ['/login'],
|
|
904
|
+
* loginPath: '/login',
|
|
905
|
+
* });
|
|
906
|
+
*
|
|
907
|
+
* export const config = {
|
|
908
|
+
* matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'],
|
|
909
|
+
* };
|
|
910
|
+
* ```
|
|
911
|
+
*/
|
|
912
|
+
declare function createAuthMiddleware(config?: AuthMiddlewareConfig): (request: NextRequest) => Promise<NextResponse<unknown>>;
|
|
913
|
+
|
|
914
|
+
interface ServerSession {
|
|
915
|
+
/**
|
|
916
|
+
* Whether user is authenticated
|
|
917
|
+
*/
|
|
918
|
+
isAuthenticated: boolean;
|
|
919
|
+
/**
|
|
920
|
+
* User's account ID from MSAL cache
|
|
921
|
+
*/
|
|
922
|
+
accountId?: string;
|
|
923
|
+
/**
|
|
924
|
+
* User's username/email
|
|
925
|
+
*/
|
|
926
|
+
username?: string;
|
|
927
|
+
/**
|
|
928
|
+
* Access token (if available in cookie)
|
|
929
|
+
* @deprecated Storing tokens in cookies is not recommended for security reasons
|
|
930
|
+
*/
|
|
931
|
+
accessToken?: string;
|
|
932
|
+
}
|
|
933
|
+
|
|
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 };
|