@chemmangat/msal-next 1.2.0 → 2.0.0

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.ts CHANGED
@@ -1,8 +1,27 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import { Configuration, LogLevel, IPublicClientApplication, PublicClientApplication, AccountInfo } from '@azure/msal-browser';
3
- import { ReactNode, CSSProperties } from 'react';
3
+ export { AccountInfo } from '@azure/msal-browser';
4
+ import { ReactNode, CSSProperties, Component, ErrorInfo, ComponentType } from 'react';
5
+ import { NextRequest, NextResponse } from 'next/server';
4
6
  export { useAccount, useIsAuthenticated, useMsal } from '@azure/msal-react';
5
7
 
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
+ }
6
25
  interface MsalAuthConfig {
7
26
  /**
8
27
  * Azure AD Application (client) ID
@@ -124,6 +143,207 @@ interface MicrosoftSignInButtonProps {
124
143
  }
125
144
  declare function MicrosoftSignInButton({ text, variant, size, useRedirect, scopes, className, style, onSuccess, onError, }: MicrosoftSignInButtonProps): react_jsx_runtime.JSX.Element;
126
145
 
146
+ interface SignOutButtonProps {
147
+ /**
148
+ * Button text
149
+ * @default 'Sign out'
150
+ */
151
+ text?: string;
152
+ /**
153
+ * Button variant
154
+ * @default 'dark'
155
+ */
156
+ variant?: 'dark' | 'light';
157
+ /**
158
+ * Button size
159
+ * @default 'medium'
160
+ */
161
+ size?: 'small' | 'medium' | 'large';
162
+ /**
163
+ * Use redirect flow instead of popup
164
+ * @default false
165
+ */
166
+ useRedirect?: boolean;
167
+ /**
168
+ * Custom className
169
+ */
170
+ className?: string;
171
+ /**
172
+ * Custom styles
173
+ */
174
+ style?: CSSProperties;
175
+ /**
176
+ * Callback on successful logout
177
+ */
178
+ onSuccess?: () => void;
179
+ /**
180
+ * Callback on error
181
+ */
182
+ onError?: (error: Error) => void;
183
+ }
184
+ /**
185
+ * SignOutButton component with Microsoft branding
186
+ *
187
+ * @example
188
+ * ```tsx
189
+ * <SignOutButton variant="light" />
190
+ * ```
191
+ */
192
+ declare function SignOutButton({ text, variant, size, useRedirect, className, style, onSuccess, onError, }: SignOutButtonProps): react_jsx_runtime.JSX.Element;
193
+
194
+ interface UserAvatarProps {
195
+ /**
196
+ * Avatar size in pixels
197
+ * @default 40
198
+ */
199
+ size?: number;
200
+ /**
201
+ * Custom className
202
+ */
203
+ className?: string;
204
+ /**
205
+ * Custom styles
206
+ */
207
+ style?: CSSProperties;
208
+ /**
209
+ * Show user name tooltip on hover
210
+ * @default true
211
+ */
212
+ showTooltip?: boolean;
213
+ /**
214
+ * Fallback image URL if MS Graph photo fails
215
+ */
216
+ fallbackImage?: string;
217
+ }
218
+ /**
219
+ * UserAvatar component that displays user photo from MS Graph with fallback initials
220
+ *
221
+ * @example
222
+ * ```tsx
223
+ * <UserAvatar size={48} />
224
+ * ```
225
+ */
226
+ declare function UserAvatar({ size, className, style, showTooltip, fallbackImage, }: UserAvatarProps): react_jsx_runtime.JSX.Element;
227
+
228
+ interface AuthStatusProps {
229
+ /**
230
+ * Custom className
231
+ */
232
+ className?: string;
233
+ /**
234
+ * Custom styles
235
+ */
236
+ style?: CSSProperties;
237
+ /**
238
+ * Show detailed status (includes username)
239
+ * @default false
240
+ */
241
+ showDetails?: boolean;
242
+ /**
243
+ * Custom render function for loading state
244
+ */
245
+ renderLoading?: () => ReactNode;
246
+ /**
247
+ * Custom render function for authenticated state
248
+ */
249
+ renderAuthenticated?: (username: string) => ReactNode;
250
+ /**
251
+ * Custom render function for unauthenticated state
252
+ */
253
+ renderUnauthenticated?: () => ReactNode;
254
+ }
255
+ /**
256
+ * AuthStatus component that shows current authentication state
257
+ *
258
+ * @example
259
+ * ```tsx
260
+ * <AuthStatus showDetails />
261
+ * ```
262
+ */
263
+ declare function AuthStatus({ className, style, showDetails, renderLoading, renderAuthenticated, renderUnauthenticated, }: AuthStatusProps): react_jsx_runtime.JSX.Element;
264
+
265
+ interface AuthGuardProps {
266
+ /**
267
+ * Content to render when authenticated
268
+ */
269
+ children: ReactNode;
270
+ /**
271
+ * Component to show while checking authentication
272
+ */
273
+ loadingComponent?: ReactNode;
274
+ /**
275
+ * Component to show when not authenticated (before redirect)
276
+ */
277
+ fallbackComponent?: ReactNode;
278
+ /**
279
+ * Use redirect flow instead of popup
280
+ * @default true
281
+ */
282
+ useRedirect?: boolean;
283
+ /**
284
+ * Scopes to request during authentication
285
+ */
286
+ scopes?: string[];
287
+ /**
288
+ * Callback when authentication is required
289
+ */
290
+ onAuthRequired?: () => void;
291
+ }
292
+ /**
293
+ * AuthGuard component that protects content and auto-redirects to login
294
+ *
295
+ * @example
296
+ * ```tsx
297
+ * <AuthGuard>
298
+ * <ProtectedContent />
299
+ * </AuthGuard>
300
+ * ```
301
+ */
302
+ declare function AuthGuard({ children, loadingComponent, fallbackComponent, useRedirect, scopes, onAuthRequired, }: AuthGuardProps): react_jsx_runtime.JSX.Element;
303
+
304
+ interface ErrorBoundaryProps {
305
+ /**
306
+ * Content to render when no error
307
+ */
308
+ children: ReactNode;
309
+ /**
310
+ * Custom error fallback component
311
+ */
312
+ fallback?: (error: Error, reset: () => void) => ReactNode;
313
+ /**
314
+ * Callback when error occurs
315
+ */
316
+ onError?: (error: Error, errorInfo: ErrorInfo) => void;
317
+ /**
318
+ * Enable debug logging
319
+ * @default false
320
+ */
321
+ debug?: boolean;
322
+ }
323
+ interface ErrorBoundaryState {
324
+ hasError: boolean;
325
+ error: Error | null;
326
+ }
327
+ /**
328
+ * Error boundary for catching authentication errors
329
+ *
330
+ * @example
331
+ * ```tsx
332
+ * <ErrorBoundary>
333
+ * <MsalAuthProvider clientId="...">
334
+ * <App />
335
+ * </MsalAuthProvider>
336
+ * </ErrorBoundary>
337
+ * ```
338
+ */
339
+ declare class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {
340
+ constructor(props: ErrorBoundaryProps);
341
+ static getDerivedStateFromError(error: Error): ErrorBoundaryState;
342
+ componentDidCatch(error: Error, errorInfo: ErrorInfo): void;
343
+ reset: () => void;
344
+ render(): ReactNode;
345
+ }
346
+
127
347
  interface UseMsalAuthReturn {
128
348
  /**
129
349
  * Current authenticated account
@@ -180,4 +400,371 @@ interface UseMsalAuthReturn {
180
400
  }
181
401
  declare function useMsalAuth(defaultScopes?: string[]): UseMsalAuthReturn;
182
402
 
183
- export { MicrosoftSignInButton, type MicrosoftSignInButtonProps, type MsalAuthConfig, MsalAuthProvider, type MsalAuthProviderProps, type UseMsalAuthReturn, getMsalInstance, useMsalAuth };
403
+ interface GraphApiOptions extends RequestInit {
404
+ /**
405
+ * Scopes required for the API call
406
+ * @default ['User.Read']
407
+ */
408
+ scopes?: string[];
409
+ /**
410
+ * API version
411
+ * @default 'v1.0'
412
+ */
413
+ version?: 'v1.0' | 'beta';
414
+ /**
415
+ * Enable debug logging
416
+ * @default false
417
+ */
418
+ debug?: boolean;
419
+ }
420
+ interface UseGraphApiReturn {
421
+ /**
422
+ * Make a GET request to MS Graph API
423
+ */
424
+ get: <T = any>(endpoint: string, options?: GraphApiOptions) => Promise<T>;
425
+ /**
426
+ * Make a POST request to MS Graph API
427
+ */
428
+ post: <T = any>(endpoint: string, body?: any, options?: GraphApiOptions) => Promise<T>;
429
+ /**
430
+ * Make a PUT request to MS Graph API
431
+ */
432
+ put: <T = any>(endpoint: string, body?: any, options?: GraphApiOptions) => Promise<T>;
433
+ /**
434
+ * Make a PATCH request to MS Graph API
435
+ */
436
+ patch: <T = any>(endpoint: string, body?: any, options?: GraphApiOptions) => Promise<T>;
437
+ /**
438
+ * Make a DELETE request to MS Graph API
439
+ */
440
+ delete: <T = any>(endpoint: string, options?: GraphApiOptions) => Promise<T>;
441
+ /**
442
+ * Make a custom request to MS Graph API
443
+ */
444
+ request: <T = any>(endpoint: string, options?: GraphApiOptions) => Promise<T>;
445
+ }
446
+ /**
447
+ * Hook for making authenticated requests to MS Graph API
448
+ *
449
+ * @example
450
+ * ```tsx
451
+ * const graph = useGraphApi();
452
+ * const user = await graph.get('/me');
453
+ * ```
454
+ */
455
+ declare function useGraphApi(): UseGraphApiReturn;
456
+
457
+ interface UserProfile {
458
+ id: string;
459
+ displayName: string;
460
+ givenName: string;
461
+ surname: string;
462
+ userPrincipalName: string;
463
+ mail: string;
464
+ jobTitle?: string;
465
+ officeLocation?: string;
466
+ mobilePhone?: string;
467
+ businessPhones?: string[];
468
+ photo?: string;
469
+ }
470
+ interface UseUserProfileReturn {
471
+ /**
472
+ * User profile data
473
+ */
474
+ profile: UserProfile | null;
475
+ /**
476
+ * Whether profile is loading
477
+ */
478
+ loading: boolean;
479
+ /**
480
+ * Error if profile fetch failed
481
+ */
482
+ error: Error | null;
483
+ /**
484
+ * Refetch user profile
485
+ */
486
+ refetch: () => Promise<void>;
487
+ /**
488
+ * Clear cached profile
489
+ */
490
+ clearCache: () => void;
491
+ }
492
+ /**
493
+ * Hook for fetching and caching user profile from MS Graph
494
+ *
495
+ * @example
496
+ * ```tsx
497
+ * const { profile, loading } = useUserProfile();
498
+ * ```
499
+ */
500
+ declare function useUserProfile(): UseUserProfileReturn;
501
+
502
+ interface UseRolesReturn {
503
+ /**
504
+ * User's Azure AD roles
505
+ */
506
+ roles: string[];
507
+ /**
508
+ * User's Azure AD groups
509
+ */
510
+ groups: string[];
511
+ /**
512
+ * Whether roles/groups are loading
513
+ */
514
+ loading: boolean;
515
+ /**
516
+ * Error if fetch failed
517
+ */
518
+ error: Error | null;
519
+ /**
520
+ * Check if user has a specific role
521
+ */
522
+ hasRole: (role: string) => boolean;
523
+ /**
524
+ * Check if user is in a specific group
525
+ */
526
+ hasGroup: (groupId: string) => boolean;
527
+ /**
528
+ * Check if user has any of the specified roles
529
+ */
530
+ hasAnyRole: (roles: string[]) => boolean;
531
+ /**
532
+ * Check if user has all of the specified roles
533
+ */
534
+ hasAllRoles: (roles: string[]) => boolean;
535
+ /**
536
+ * Refetch roles and groups
537
+ */
538
+ refetch: () => Promise<void>;
539
+ }
540
+ /**
541
+ * Hook for fetching user's Azure AD roles and groups
542
+ *
543
+ * @example
544
+ * ```tsx
545
+ * const { roles, hasRole } = useRoles();
546
+ * if (hasRole('Admin')) {
547
+ * // Show admin content
548
+ * }
549
+ * ```
550
+ */
551
+ declare function useRoles(): UseRolesReturn;
552
+
553
+ declare function createMsalConfig(config: MsalAuthConfig): Configuration;
554
+
555
+ interface WithAuthOptions extends Omit<AuthGuardProps, 'children'> {
556
+ /**
557
+ * Display name for the wrapped component (for debugging)
558
+ */
559
+ displayName?: string;
560
+ }
561
+ /**
562
+ * Higher-order component for protecting pages/components
563
+ *
564
+ * @example
565
+ * ```tsx
566
+ * const ProtectedPage = withAuth(MyPage);
567
+ *
568
+ * // With options
569
+ * const ProtectedPage = withAuth(MyPage, {
570
+ * useRedirect: true,
571
+ * scopes: ['User.Read', 'Mail.Read']
572
+ * });
573
+ * ```
574
+ */
575
+ declare function withAuth<P extends object>(Component: ComponentType<P>, options?: WithAuthOptions): ComponentType<P>;
576
+
577
+ /**
578
+ * Retry configuration for token acquisition
579
+ */
580
+ interface RetryConfig {
581
+ /**
582
+ * Maximum number of retry attempts
583
+ * @default 3
584
+ */
585
+ maxRetries?: number;
586
+ /**
587
+ * Initial delay in milliseconds
588
+ * @default 1000
589
+ */
590
+ initialDelay?: number;
591
+ /**
592
+ * Maximum delay in milliseconds
593
+ * @default 10000
594
+ */
595
+ maxDelay?: number;
596
+ /**
597
+ * Backoff multiplier
598
+ * @default 2
599
+ */
600
+ backoffMultiplier?: number;
601
+ /**
602
+ * Enable debug logging
603
+ * @default false
604
+ */
605
+ debug?: boolean;
606
+ }
607
+ /**
608
+ * Exponential backoff retry utility for token acquisition
609
+ *
610
+ * @example
611
+ * ```tsx
612
+ * const token = await retryWithBackoff(
613
+ * () => acquireTokenSilent(scopes),
614
+ * { maxRetries: 3, debug: true }
615
+ * );
616
+ * ```
617
+ */
618
+ declare function retryWithBackoff<T>(fn: () => Promise<T>, config?: RetryConfig): Promise<T>;
619
+ /**
620
+ * Create a retry wrapper for a function
621
+ *
622
+ * @example
623
+ * ```tsx
624
+ * const acquireTokenWithRetry = createRetryWrapper(acquireToken, {
625
+ * maxRetries: 3,
626
+ * debug: true
627
+ * });
628
+ *
629
+ * const token = await acquireTokenWithRetry(scopes);
630
+ * ```
631
+ */
632
+ declare function createRetryWrapper<TArgs extends any[], TReturn>(fn: (...args: TArgs) => Promise<TReturn>, config?: RetryConfig): (...args: TArgs) => Promise<TReturn>;
633
+
634
+ /**
635
+ * Debug logger configuration
636
+ */
637
+ interface DebugLoggerConfig {
638
+ /**
639
+ * Enable debug mode
640
+ * @default false
641
+ */
642
+ enabled?: boolean;
643
+ /**
644
+ * Prefix for log messages
645
+ * @default '[MSAL-Next]'
646
+ */
647
+ prefix?: string;
648
+ /**
649
+ * Show timestamps
650
+ * @default true
651
+ */
652
+ showTimestamp?: boolean;
653
+ /**
654
+ * Log level
655
+ * @default 'info'
656
+ */
657
+ level?: 'error' | 'warn' | 'info' | 'debug';
658
+ }
659
+ declare class DebugLogger {
660
+ private config;
661
+ constructor(config?: DebugLoggerConfig);
662
+ private shouldLog;
663
+ private formatMessage;
664
+ error(message: string, data?: any): void;
665
+ warn(message: string, data?: any): void;
666
+ info(message: string, data?: any): void;
667
+ debug(message: string, data?: any): void;
668
+ group(label: string): void;
669
+ groupEnd(): void;
670
+ setEnabled(enabled: boolean): void;
671
+ setLevel(level: DebugLoggerConfig['level']): void;
672
+ }
673
+ /**
674
+ * Get or create the global debug logger
675
+ *
676
+ * @example
677
+ * ```tsx
678
+ * const logger = getDebugLogger({ enabled: true, level: 'debug' });
679
+ * logger.info('User logged in', { username: 'user@example.com' });
680
+ * ```
681
+ */
682
+ declare function getDebugLogger(config?: DebugLoggerConfig): DebugLogger;
683
+ /**
684
+ * Create a scoped logger with a custom prefix
685
+ *
686
+ * @example
687
+ * ```tsx
688
+ * const logger = createScopedLogger('GraphAPI', { enabled: true });
689
+ * logger.info('Fetching user profile');
690
+ * ```
691
+ */
692
+ declare function createScopedLogger(scope: string, config?: DebugLoggerConfig): DebugLogger;
693
+
694
+ interface AuthMiddlewareConfig {
695
+ /**
696
+ * Routes that require authentication
697
+ * @example ['/dashboard', '/profile', '/api/protected']
698
+ */
699
+ protectedRoutes?: string[];
700
+ /**
701
+ * Routes that should be accessible only when NOT authenticated
702
+ * @example ['/login', '/signup']
703
+ */
704
+ publicOnlyRoutes?: string[];
705
+ /**
706
+ * Login page path
707
+ * @default '/login'
708
+ */
709
+ loginPath?: string;
710
+ /**
711
+ * Redirect path after login
712
+ * @default '/'
713
+ */
714
+ redirectAfterLogin?: string;
715
+ /**
716
+ * Cookie name for session
717
+ * @default 'msal.account'
718
+ */
719
+ sessionCookie?: string;
720
+ /**
721
+ * Custom authentication check function
722
+ */
723
+ isAuthenticated?: (request: NextRequest) => boolean | Promise<boolean>;
724
+ /**
725
+ * Enable debug logging
726
+ * @default false
727
+ */
728
+ debug?: boolean;
729
+ }
730
+ /**
731
+ * Creates authentication middleware for Next.js App Router
732
+ *
733
+ * @example
734
+ * ```tsx
735
+ * // middleware.ts
736
+ * import { createAuthMiddleware } from '@chemmangat/msal-next';
737
+ *
738
+ * export const middleware = createAuthMiddleware({
739
+ * protectedRoutes: ['/dashboard', '/profile'],
740
+ * publicOnlyRoutes: ['/login'],
741
+ * loginPath: '/login',
742
+ * });
743
+ *
744
+ * export const config = {
745
+ * matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'],
746
+ * };
747
+ * ```
748
+ */
749
+ declare function createAuthMiddleware(config?: AuthMiddlewareConfig): (request: NextRequest) => Promise<NextResponse<unknown>>;
750
+
751
+ interface ServerSession {
752
+ /**
753
+ * Whether user is authenticated
754
+ */
755
+ isAuthenticated: boolean;
756
+ /**
757
+ * User's account ID from MSAL cache
758
+ */
759
+ accountId?: string;
760
+ /**
761
+ * User's username/email
762
+ */
763
+ username?: string;
764
+ /**
765
+ * Access token (if available in cookie)
766
+ */
767
+ accessToken?: string;
768
+ }
769
+
770
+ export { AuthGuard, type AuthGuardProps, type AuthMiddlewareConfig, AuthStatus, type AuthStatusProps, type CustomTokenClaims, type DebugLoggerConfig, ErrorBoundary, type ErrorBoundaryProps, type GraphApiOptions, 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 WithAuthOptions, createAuthMiddleware, createMsalConfig, createRetryWrapper, createScopedLogger, getDebugLogger, getMsalInstance, retryWithBackoff, useGraphApi, useMsalAuth, useRoles, useUserProfile, withAuth };