@chemmangat/msal-next 4.0.1 → 4.1.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/CHANGELOG.md +351 -1
- package/README.md +580 -526
- package/SECURITY.md +422 -110
- package/TROUBLESHOOTING.md +380 -188
- package/dist/index.d.mts +332 -8
- package/dist/index.d.ts +332 -8
- package/dist/index.js +2382 -2
- package/dist/index.mjs +2320 -2
- package/dist/server.js +89 -1
- package/dist/server.mjs +86 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -264,6 +264,41 @@ interface MsalAuthConfig {
|
|
|
264
264
|
* ```
|
|
265
265
|
*/
|
|
266
266
|
onInitialized?: (instance: IPublicClientApplication) => void;
|
|
267
|
+
/**
|
|
268
|
+
* Enable automatic token refresh
|
|
269
|
+
*
|
|
270
|
+
* @remarks
|
|
271
|
+
* Automatically refreshes access tokens before they expire to prevent
|
|
272
|
+
* session interruptions. Tokens are refreshed silently in the background.
|
|
273
|
+
*
|
|
274
|
+
* @defaultValue false
|
|
275
|
+
*
|
|
276
|
+
* @example
|
|
277
|
+
* ```tsx
|
|
278
|
+
* <MSALProvider
|
|
279
|
+
* clientId="..."
|
|
280
|
+
* autoRefreshToken={true}
|
|
281
|
+
* refreshBeforeExpiry={300} // Refresh 5 min before expiry
|
|
282
|
+
* >
|
|
283
|
+
* {children}
|
|
284
|
+
* </MSALProvider>
|
|
285
|
+
* ```
|
|
286
|
+
*/
|
|
287
|
+
autoRefreshToken?: boolean;
|
|
288
|
+
/**
|
|
289
|
+
* Refresh token this many seconds before expiry
|
|
290
|
+
*
|
|
291
|
+
* @remarks
|
|
292
|
+
* Only used when autoRefreshToken is enabled.
|
|
293
|
+
*
|
|
294
|
+
* @defaultValue 300 (5 minutes)
|
|
295
|
+
*
|
|
296
|
+
* @example
|
|
297
|
+
* ```tsx
|
|
298
|
+
* refreshBeforeExpiry={600} // Refresh 10 minutes before expiry
|
|
299
|
+
* ```
|
|
300
|
+
*/
|
|
301
|
+
refreshBeforeExpiry?: number;
|
|
267
302
|
}
|
|
268
303
|
/**
|
|
269
304
|
* Props for MsalAuthProvider component
|
|
@@ -283,7 +318,7 @@ interface MsalAuthProviderProps extends MsalAuthConfig {
|
|
|
283
318
|
* @returns The MSAL instance or null if not initialized
|
|
284
319
|
*/
|
|
285
320
|
declare function getMsalInstance(): PublicClientApplication | null;
|
|
286
|
-
declare function MsalAuthProvider({ children, loadingComponent, onInitialized, ...config }: MsalAuthProviderProps): react_jsx_runtime.JSX.Element;
|
|
321
|
+
declare function MsalAuthProvider({ children, loadingComponent, onInitialized, autoRefreshToken, refreshBeforeExpiry, ...config }: MsalAuthProviderProps): react_jsx_runtime.JSX.Element;
|
|
287
322
|
|
|
288
323
|
/**
|
|
289
324
|
* Zero-Config Protected Routes - Type Definitions
|
|
@@ -393,12 +428,15 @@ interface MSALProviderProps extends MsalAuthProviderProps {
|
|
|
393
428
|
}
|
|
394
429
|
/**
|
|
395
430
|
* Pre-configured MSALProvider component for Next.js App Router layouts.
|
|
396
|
-
*
|
|
397
|
-
*
|
|
431
|
+
*
|
|
432
|
+
* @remarks
|
|
433
|
+
* This component is already marked as 'use client' internally, so you can import
|
|
434
|
+
* and use it directly in your server-side layout.tsx without adding 'use client'
|
|
435
|
+
* to your layout file.
|
|
398
436
|
*
|
|
399
437
|
* @example
|
|
400
438
|
* ```tsx
|
|
401
|
-
* // app/layout.tsx
|
|
439
|
+
* // app/layout.tsx (Server Component - no 'use client' needed!)
|
|
402
440
|
* import { MSALProvider } from '@chemmangat/msal-next'
|
|
403
441
|
*
|
|
404
442
|
* export default function RootLayout({ children }) {
|
|
@@ -416,6 +454,13 @@ interface MSALProviderProps extends MsalAuthProviderProps {
|
|
|
416
454
|
* )
|
|
417
455
|
* }
|
|
418
456
|
* ```
|
|
457
|
+
*
|
|
458
|
+
* @security
|
|
459
|
+
* - All authentication happens client-side (browser)
|
|
460
|
+
* - Tokens are never sent to your Next.js server
|
|
461
|
+
* - Uses Microsoft's official MSAL library
|
|
462
|
+
* - Supports secure token storage (sessionStorage/localStorage)
|
|
463
|
+
* - No server-side token handling required
|
|
419
464
|
*/
|
|
420
465
|
declare function MSALProvider({ children, protection, ...props }: MSALProviderProps): react_jsx_runtime.JSX.Element;
|
|
421
466
|
|
|
@@ -748,24 +793,116 @@ interface UseGraphApiReturn {
|
|
|
748
793
|
*/
|
|
749
794
|
declare function useGraphApi(): UseGraphApiReturn;
|
|
750
795
|
|
|
796
|
+
/**
|
|
797
|
+
* Complete Microsoft Graph User Profile Types
|
|
798
|
+
* Based on Microsoft Graph /me endpoint
|
|
799
|
+
*
|
|
800
|
+
* @see https://learn.microsoft.com/en-us/graph/api/user-get
|
|
801
|
+
*/
|
|
802
|
+
/**
|
|
803
|
+
* Complete user profile from Microsoft Graph /me endpoint
|
|
804
|
+
*
|
|
805
|
+
* @remarks
|
|
806
|
+
* This interface includes all common fields returned by the Microsoft Graph /me endpoint.
|
|
807
|
+
* You can extend this interface with custom fields specific to your organization.
|
|
808
|
+
*
|
|
809
|
+
* @example
|
|
810
|
+
* ```tsx
|
|
811
|
+
* // Basic usage
|
|
812
|
+
* const { profile } = useUserProfile();
|
|
813
|
+
* console.log(profile?.department); // Now type-safe!
|
|
814
|
+
*
|
|
815
|
+
* // With custom fields
|
|
816
|
+
* interface MyUserProfile extends UserProfile {
|
|
817
|
+
* customField: string;
|
|
818
|
+
* }
|
|
819
|
+
*
|
|
820
|
+
* const { profile } = useUserProfile<MyUserProfile>();
|
|
821
|
+
* console.log(profile?.customField);
|
|
822
|
+
* ```
|
|
823
|
+
*/
|
|
751
824
|
interface UserProfile {
|
|
825
|
+
/** Unique identifier for the user */
|
|
752
826
|
id: string;
|
|
827
|
+
/** User's display name */
|
|
753
828
|
displayName: string;
|
|
829
|
+
/** User's first name */
|
|
754
830
|
givenName: string;
|
|
831
|
+
/** User's last name */
|
|
755
832
|
surname: string;
|
|
833
|
+
/** User principal name (UPN) - typically the email used for login */
|
|
756
834
|
userPrincipalName: string;
|
|
835
|
+
/** Primary email address */
|
|
757
836
|
mail: string;
|
|
837
|
+
/** Job title */
|
|
758
838
|
jobTitle?: string;
|
|
839
|
+
/** Department name */
|
|
840
|
+
department?: string;
|
|
841
|
+
/** Company name */
|
|
842
|
+
companyName?: string;
|
|
843
|
+
/** Office location */
|
|
759
844
|
officeLocation?: string;
|
|
845
|
+
/** Mobile phone number */
|
|
760
846
|
mobilePhone?: string;
|
|
847
|
+
/** Business phone numbers */
|
|
761
848
|
businessPhones?: string[];
|
|
849
|
+
/** Preferred language (e.g., "en-US") */
|
|
850
|
+
preferredLanguage?: string;
|
|
851
|
+
/** Employee ID */
|
|
852
|
+
employeeId?: string;
|
|
853
|
+
/** Employee hire date */
|
|
854
|
+
employeeHireDate?: string;
|
|
855
|
+
/** Employee type (e.g., "Employee", "Contractor") */
|
|
856
|
+
employeeType?: string;
|
|
857
|
+
/** Country/region */
|
|
858
|
+
country?: string;
|
|
859
|
+
/** City */
|
|
860
|
+
city?: string;
|
|
861
|
+
/** State or province */
|
|
862
|
+
state?: string;
|
|
863
|
+
/** Street address */
|
|
864
|
+
streetAddress?: string;
|
|
865
|
+
/** Postal code */
|
|
866
|
+
postalCode?: string;
|
|
867
|
+
/** Usage location (ISO 3166 country code) */
|
|
868
|
+
usageLocation?: string;
|
|
869
|
+
/** Manager's user ID */
|
|
870
|
+
manager?: string;
|
|
871
|
+
/** About me / bio */
|
|
872
|
+
aboutMe?: string;
|
|
873
|
+
/** Birthday */
|
|
874
|
+
birthday?: string;
|
|
875
|
+
/** Interests */
|
|
876
|
+
interests?: string[];
|
|
877
|
+
/** Skills */
|
|
878
|
+
skills?: string[];
|
|
879
|
+
/** Schools attended */
|
|
880
|
+
schools?: string[];
|
|
881
|
+
/** Past projects */
|
|
882
|
+
pastProjects?: string[];
|
|
883
|
+
/** Responsibilities */
|
|
884
|
+
responsibilities?: string[];
|
|
885
|
+
/** My site URL */
|
|
886
|
+
mySite?: string;
|
|
887
|
+
/** Fax number */
|
|
888
|
+
faxNumber?: string;
|
|
889
|
+
/** Account enabled status */
|
|
890
|
+
accountEnabled?: boolean;
|
|
891
|
+
/** Age group (e.g., "Adult", "Minor") */
|
|
892
|
+
ageGroup?: string;
|
|
893
|
+
/** User type (e.g., "Member", "Guest") */
|
|
894
|
+
userType?: string;
|
|
895
|
+
/** Profile photo URL (blob URL created by the library) */
|
|
762
896
|
photo?: string;
|
|
763
897
|
}
|
|
764
|
-
|
|
898
|
+
/**
|
|
899
|
+
* Return type for useUserProfile hook
|
|
900
|
+
*/
|
|
901
|
+
interface UseUserProfileReturn<T extends UserProfile = UserProfile> {
|
|
765
902
|
/**
|
|
766
903
|
* User profile data
|
|
767
904
|
*/
|
|
768
|
-
profile:
|
|
905
|
+
profile: T | null;
|
|
769
906
|
/**
|
|
770
907
|
* Whether profile is loading
|
|
771
908
|
*/
|
|
@@ -783,15 +920,27 @@ interface UseUserProfileReturn {
|
|
|
783
920
|
*/
|
|
784
921
|
clearCache: () => void;
|
|
785
922
|
}
|
|
923
|
+
|
|
786
924
|
/**
|
|
787
925
|
* Hook for fetching and caching user profile from MS Graph
|
|
788
926
|
*
|
|
927
|
+
* @remarks
|
|
928
|
+
* Supports generic type parameter for custom profile fields.
|
|
929
|
+
*
|
|
789
930
|
* @example
|
|
790
931
|
* ```tsx
|
|
932
|
+
* // Basic usage
|
|
791
933
|
* const { profile, loading } = useUserProfile();
|
|
934
|
+
* console.log(profile?.department); // Now available!
|
|
935
|
+
*
|
|
936
|
+
* // With custom fields
|
|
937
|
+
* interface MyProfile extends UserProfile {
|
|
938
|
+
* customField: string;
|
|
939
|
+
* }
|
|
940
|
+
* const { profile } = useUserProfile<MyProfile>();
|
|
792
941
|
* ```
|
|
793
942
|
*/
|
|
794
|
-
declare function useUserProfile(): UseUserProfileReturn
|
|
943
|
+
declare function useUserProfile<T extends UserProfile = UserProfile>(): UseUserProfileReturn<T>;
|
|
795
944
|
|
|
796
945
|
interface UseRolesReturn {
|
|
797
946
|
/**
|
|
@@ -844,6 +993,80 @@ interface UseRolesReturn {
|
|
|
844
993
|
*/
|
|
845
994
|
declare function useRoles(): UseRolesReturn;
|
|
846
995
|
|
|
996
|
+
/**
|
|
997
|
+
* Automatic token refresh hook
|
|
998
|
+
* Refreshes tokens before they expire to prevent session interruptions
|
|
999
|
+
*/
|
|
1000
|
+
interface UseTokenRefreshOptions {
|
|
1001
|
+
/**
|
|
1002
|
+
* Enable automatic token refresh
|
|
1003
|
+
* @default true
|
|
1004
|
+
*/
|
|
1005
|
+
enabled?: boolean;
|
|
1006
|
+
/**
|
|
1007
|
+
* Refresh token this many seconds before expiry
|
|
1008
|
+
* @default 300 (5 minutes)
|
|
1009
|
+
*/
|
|
1010
|
+
refreshBeforeExpiry?: number;
|
|
1011
|
+
/**
|
|
1012
|
+
* Scopes to refresh
|
|
1013
|
+
* @default ['User.Read']
|
|
1014
|
+
*/
|
|
1015
|
+
scopes?: string[];
|
|
1016
|
+
/**
|
|
1017
|
+
* Callback when token is refreshed
|
|
1018
|
+
*/
|
|
1019
|
+
onRefresh?: (expiresIn: number) => void;
|
|
1020
|
+
/**
|
|
1021
|
+
* Callback when refresh fails
|
|
1022
|
+
*/
|
|
1023
|
+
onError?: (error: Error) => void;
|
|
1024
|
+
}
|
|
1025
|
+
interface UseTokenRefreshReturn {
|
|
1026
|
+
/**
|
|
1027
|
+
* Seconds until token expires
|
|
1028
|
+
*/
|
|
1029
|
+
expiresIn: number | null;
|
|
1030
|
+
/**
|
|
1031
|
+
* Whether token is expiring soon
|
|
1032
|
+
*/
|
|
1033
|
+
isExpiringSoon: boolean;
|
|
1034
|
+
/**
|
|
1035
|
+
* Manually trigger token refresh
|
|
1036
|
+
*/
|
|
1037
|
+
refresh: () => Promise<void>;
|
|
1038
|
+
/**
|
|
1039
|
+
* Last refresh timestamp
|
|
1040
|
+
*/
|
|
1041
|
+
lastRefresh: Date | null;
|
|
1042
|
+
}
|
|
1043
|
+
/**
|
|
1044
|
+
* Hook for automatic token refresh
|
|
1045
|
+
*
|
|
1046
|
+
* @remarks
|
|
1047
|
+
* Automatically refreshes access tokens before they expire to prevent
|
|
1048
|
+
* session interruptions. Runs in the background without user interaction.
|
|
1049
|
+
*
|
|
1050
|
+
* @example
|
|
1051
|
+
* ```tsx
|
|
1052
|
+
* // Basic usage - automatic refresh
|
|
1053
|
+
* useTokenRefresh();
|
|
1054
|
+
*
|
|
1055
|
+
* // With options
|
|
1056
|
+
* const { expiresIn, isExpiringSoon } = useTokenRefresh({
|
|
1057
|
+
* refreshBeforeExpiry: 600, // 10 minutes
|
|
1058
|
+
* scopes: ['User.Read', 'Mail.Read'],
|
|
1059
|
+
* onRefresh: (expiresIn) => console.log(`Token refreshed, expires in ${expiresIn}s`),
|
|
1060
|
+
* });
|
|
1061
|
+
*
|
|
1062
|
+
* // Show warning when expiring soon
|
|
1063
|
+
* if (isExpiringSoon) {
|
|
1064
|
+
* return <div>Your session will expire soon</div>;
|
|
1065
|
+
* }
|
|
1066
|
+
* ```
|
|
1067
|
+
*/
|
|
1068
|
+
declare function useTokenRefresh(options?: UseTokenRefreshOptions): UseTokenRefreshReturn;
|
|
1069
|
+
|
|
847
1070
|
declare function createMsalConfig(config: MsalAuthConfig): Configuration;
|
|
848
1071
|
|
|
849
1072
|
interface WithAuthOptions extends Omit<AuthGuardProps, 'children'> {
|
|
@@ -1114,6 +1337,107 @@ declare function isValidScope(scope: string): boolean;
|
|
|
1114
1337
|
*/
|
|
1115
1338
|
declare function validateScopes(scopes: string[]): boolean;
|
|
1116
1339
|
|
|
1340
|
+
/**
|
|
1341
|
+
* Development-mode configuration validator
|
|
1342
|
+
* Helps developers catch common configuration mistakes early
|
|
1343
|
+
*/
|
|
1344
|
+
|
|
1345
|
+
interface ValidationResult {
|
|
1346
|
+
valid: boolean;
|
|
1347
|
+
warnings: ValidationWarning[];
|
|
1348
|
+
errors: ValidationError[];
|
|
1349
|
+
}
|
|
1350
|
+
interface ValidationWarning {
|
|
1351
|
+
field: string;
|
|
1352
|
+
message: string;
|
|
1353
|
+
fix: string;
|
|
1354
|
+
}
|
|
1355
|
+
interface ValidationError {
|
|
1356
|
+
field: string;
|
|
1357
|
+
message: string;
|
|
1358
|
+
fix: string;
|
|
1359
|
+
}
|
|
1360
|
+
/**
|
|
1361
|
+
* Validate MSAL configuration in development mode
|
|
1362
|
+
*
|
|
1363
|
+
* @remarks
|
|
1364
|
+
* This function only runs in development mode and caches results.
|
|
1365
|
+
* It checks for common configuration mistakes and provides helpful warnings.
|
|
1366
|
+
*
|
|
1367
|
+
* @example
|
|
1368
|
+
* ```tsx
|
|
1369
|
+
* const result = validateConfig({
|
|
1370
|
+
* clientId: process.env.NEXT_PUBLIC_AZURE_AD_CLIENT_ID!,
|
|
1371
|
+
* tenantId: process.env.NEXT_PUBLIC_AZURE_AD_TENANT_ID,
|
|
1372
|
+
* });
|
|
1373
|
+
*
|
|
1374
|
+
* if (!result.valid) {
|
|
1375
|
+
* console.warn('Configuration issues detected');
|
|
1376
|
+
* }
|
|
1377
|
+
* ```
|
|
1378
|
+
*/
|
|
1379
|
+
declare function validateConfig(config: MsalAuthConfig): ValidationResult;
|
|
1380
|
+
/**
|
|
1381
|
+
* Display validation results in console with colors and emojis
|
|
1382
|
+
*/
|
|
1383
|
+
declare function displayValidationResults(result: ValidationResult): void;
|
|
1384
|
+
|
|
1385
|
+
/**
|
|
1386
|
+
* Enhanced MSAL error class with actionable messages
|
|
1387
|
+
*/
|
|
1388
|
+
declare class MsalError extends Error {
|
|
1389
|
+
/** Original error code from MSAL */
|
|
1390
|
+
readonly code?: string;
|
|
1391
|
+
/** Actionable fix instructions */
|
|
1392
|
+
readonly fix?: string;
|
|
1393
|
+
/** Documentation link */
|
|
1394
|
+
readonly docs?: string;
|
|
1395
|
+
/** Original error object */
|
|
1396
|
+
readonly originalError?: unknown;
|
|
1397
|
+
constructor(error: unknown);
|
|
1398
|
+
/**
|
|
1399
|
+
* Parse error and extract actionable information
|
|
1400
|
+
*/
|
|
1401
|
+
private static parseError;
|
|
1402
|
+
/**
|
|
1403
|
+
* Format error for console logging with colors (development only)
|
|
1404
|
+
*/
|
|
1405
|
+
toConsoleString(): string;
|
|
1406
|
+
/**
|
|
1407
|
+
* Check if error is a user cancellation (not a real error)
|
|
1408
|
+
*/
|
|
1409
|
+
isUserCancellation(): boolean;
|
|
1410
|
+
/**
|
|
1411
|
+
* Check if error requires user interaction
|
|
1412
|
+
*/
|
|
1413
|
+
requiresInteraction(): boolean;
|
|
1414
|
+
}
|
|
1415
|
+
/**
|
|
1416
|
+
* Wrap MSAL errors with enhanced error information
|
|
1417
|
+
*
|
|
1418
|
+
* @example
|
|
1419
|
+
* ```tsx
|
|
1420
|
+
* try {
|
|
1421
|
+
* await loginRedirect();
|
|
1422
|
+
* } catch (error) {
|
|
1423
|
+
* const msalError = wrapMsalError(error);
|
|
1424
|
+
*
|
|
1425
|
+
* if (msalError.isUserCancellation()) {
|
|
1426
|
+
* // User cancelled, ignore
|
|
1427
|
+
* return;
|
|
1428
|
+
* }
|
|
1429
|
+
*
|
|
1430
|
+
* console.error(msalError.toConsoleString());
|
|
1431
|
+
* throw msalError;
|
|
1432
|
+
* }
|
|
1433
|
+
* ```
|
|
1434
|
+
*/
|
|
1435
|
+
declare function wrapMsalError(error: unknown): MsalError;
|
|
1436
|
+
/**
|
|
1437
|
+
* Create error for missing environment variable
|
|
1438
|
+
*/
|
|
1439
|
+
declare function createMissingEnvVarError(varName: string): MsalError;
|
|
1440
|
+
|
|
1117
1441
|
interface ProtectedPageProps {
|
|
1118
1442
|
children: ReactNode;
|
|
1119
1443
|
config: PageAuthConfig;
|
|
@@ -1224,4 +1548,4 @@ interface ServerSession {
|
|
|
1224
1548
|
accessToken?: string;
|
|
1225
1549
|
}
|
|
1226
1550
|
|
|
1227
|
-
export { AuthGuard, type AuthGuardProps, type AuthMiddlewareConfig, type AuthProtectionConfig, AuthStatus, type AuthStatusProps, type CustomTokenClaims, type DebugLoggerConfig, ErrorBoundary, type ErrorBoundaryProps, type GraphApiOptions, MSALProvider, MicrosoftSignInButton, type MicrosoftSignInButtonProps, type MsalAuthConfig, MsalAuthProvider, type MsalAuthProviderProps, type PageAuthConfig, ProtectedPage, 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, withPageAuth };
|
|
1551
|
+
export { AuthGuard, type AuthGuardProps, type AuthMiddlewareConfig, type AuthProtectionConfig, AuthStatus, type AuthStatusProps, type CustomTokenClaims, type DebugLoggerConfig, ErrorBoundary, type ErrorBoundaryProps, type GraphApiOptions, MSALProvider, MicrosoftSignInButton, type MicrosoftSignInButtonProps, type MsalAuthConfig, MsalAuthProvider, type MsalAuthProviderProps, MsalError, type PageAuthConfig, ProtectedPage, type RetryConfig, type ServerSession, SignOutButton, type SignOutButtonProps, type UseGraphApiReturn, type UseMsalAuthReturn, type UseRolesReturn, type UseTokenRefreshOptions, type UseTokenRefreshReturn, type UseUserProfileReturn, UserAvatar, type UserAvatarProps, type UserProfile, type ValidatedAccountData, type ValidationError, type ValidationResult, type ValidationWarning, type WithAuthOptions, createAuthMiddleware, createMissingEnvVarError, createMsalConfig, createRetryWrapper, createScopedLogger, displayValidationResults, getDebugLogger, getMsalInstance, isValidAccountData, isValidRedirectUri, isValidScope, retryWithBackoff, safeJsonParse, sanitizeError, useGraphApi, useMsalAuth, useRoles, useTokenRefresh, useUserProfile, validateConfig, validateScopes, withAuth, withPageAuth, wrapMsalError };
|