@chemmangat/msal-next 2.1.2 → 3.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/README.md +123 -4
- package/dist/index.d.mts +95 -2
- package/dist/index.d.ts +95 -2
- package/dist/index.js +2 -1415
- package/dist/index.mjs +2 -1378
- package/dist/server.js +1 -91
- package/dist/server.mjs +1 -88
- package/package.json +3 -3
- package/dist/index.js.map +0 -1
- package/dist/index.mjs.map +0 -1
- package/dist/server.js.map +0 -1
- package/dist/server.mjs.map +0 -1
package/dist/server.js
CHANGED
|
@@ -1,91 +1 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
var headers = require('next/headers');
|
|
4
|
-
|
|
5
|
-
// src/utils/getServerSession.ts
|
|
6
|
-
|
|
7
|
-
// src/utils/validation.ts
|
|
8
|
-
function safeJsonParse(jsonString, validator) {
|
|
9
|
-
try {
|
|
10
|
-
const parsed = JSON.parse(jsonString);
|
|
11
|
-
if (validator(parsed)) {
|
|
12
|
-
return parsed;
|
|
13
|
-
}
|
|
14
|
-
console.warn("[Validation] JSON validation failed");
|
|
15
|
-
return null;
|
|
16
|
-
} catch (error) {
|
|
17
|
-
console.error("[Validation] JSON parse error:", error);
|
|
18
|
-
return null;
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
function isValidAccountData(data) {
|
|
22
|
-
return typeof data === "object" && data !== null && typeof data.homeAccountId === "string" && data.homeAccountId.length > 0 && typeof data.username === "string" && data.username.length > 0 && (data.name === void 0 || typeof data.name === "string");
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
// src/utils/getServerSession.ts
|
|
26
|
-
async function getServerSession() {
|
|
27
|
-
try {
|
|
28
|
-
const cookieStore = await headers.cookies();
|
|
29
|
-
const headersList = await headers.headers();
|
|
30
|
-
const msalAccount = cookieStore.get("msal.account");
|
|
31
|
-
const msalToken = cookieStore.get("msal.token");
|
|
32
|
-
if (msalAccount?.value) {
|
|
33
|
-
const accountData = safeJsonParse(
|
|
34
|
-
msalAccount.value,
|
|
35
|
-
isValidAccountData
|
|
36
|
-
);
|
|
37
|
-
if (accountData) {
|
|
38
|
-
return {
|
|
39
|
-
isAuthenticated: true,
|
|
40
|
-
accountId: accountData.homeAccountId,
|
|
41
|
-
username: accountData.username,
|
|
42
|
-
accessToken: msalToken?.value
|
|
43
|
-
};
|
|
44
|
-
} else {
|
|
45
|
-
console.warn("[ServerSession] Invalid account data in cookie");
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
const authHeader = headersList.get("x-msal-authenticated");
|
|
49
|
-
if (authHeader === "true") {
|
|
50
|
-
const username = headersList.get("x-msal-username");
|
|
51
|
-
return {
|
|
52
|
-
isAuthenticated: true,
|
|
53
|
-
username: username || void 0
|
|
54
|
-
};
|
|
55
|
-
}
|
|
56
|
-
return {
|
|
57
|
-
isAuthenticated: false
|
|
58
|
-
};
|
|
59
|
-
} catch (error) {
|
|
60
|
-
console.error("[ServerSession] Error reading session:", error);
|
|
61
|
-
return {
|
|
62
|
-
isAuthenticated: false
|
|
63
|
-
};
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
async function setServerSessionCookie(account, accessToken) {
|
|
67
|
-
try {
|
|
68
|
-
const accountData = {
|
|
69
|
-
homeAccountId: account.homeAccountId,
|
|
70
|
-
username: account.username,
|
|
71
|
-
name: account.name
|
|
72
|
-
};
|
|
73
|
-
await fetch("/api/auth/session", {
|
|
74
|
-
method: "POST",
|
|
75
|
-
headers: {
|
|
76
|
-
"Content-Type": "application/json"
|
|
77
|
-
},
|
|
78
|
-
body: JSON.stringify({
|
|
79
|
-
account: accountData,
|
|
80
|
-
token: accessToken
|
|
81
|
-
})
|
|
82
|
-
});
|
|
83
|
-
} catch (error) {
|
|
84
|
-
console.error("[ServerSession] Failed to set session cookie:", error);
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
exports.getServerSession = getServerSession;
|
|
89
|
-
exports.setServerSessionCookie = setServerSessionCookie;
|
|
90
|
-
//# sourceMappingURL=server.js.map
|
|
91
|
-
//# sourceMappingURL=server.js.map
|
|
1
|
+
'use strict';var headers=require('next/headers');function o(e,r){try{let n=JSON.parse(e);return r(n)?n:(console.warn("[Validation] JSON validation failed"),null)}catch(n){return console.error("[Validation] JSON parse error:",n),null}}function s(e){return typeof e=="object"&&e!==null&&typeof e.homeAccountId=="string"&&e.homeAccountId.length>0&&typeof e.username=="string"&&e.username.length>0&&(e.name===void 0||typeof e.name=="string")}async function u(){try{let e=await headers.cookies(),r=await headers.headers(),n=e.get("msal.account"),a=e.get("msal.token");if(n?.value){let t=o(n.value,s);if(t)return {isAuthenticated:!0,accountId:t.homeAccountId,username:t.username,accessToken:a?.value};console.warn("[ServerSession] Invalid account data in cookie");}return r.get("x-msal-authenticated")==="true"?{isAuthenticated:!0,username:r.get("x-msal-username")||void 0}:{isAuthenticated:!1}}catch(e){return console.error("[ServerSession] Error reading session:",e),{isAuthenticated:false}}}async function l(e,r){try{let n={homeAccountId:e.homeAccountId,username:e.username,name:e.name};await fetch("/api/auth/session",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({account:n,token:r})});}catch(n){console.error("[ServerSession] Failed to set session cookie:",n);}}exports.getServerSession=u;exports.setServerSessionCookie=l;
|
package/dist/server.mjs
CHANGED
|
@@ -1,88 +1 @@
|
|
|
1
|
-
import { cookies, headers }
|
|
2
|
-
|
|
3
|
-
// src/utils/getServerSession.ts
|
|
4
|
-
|
|
5
|
-
// src/utils/validation.ts
|
|
6
|
-
function safeJsonParse(jsonString, validator) {
|
|
7
|
-
try {
|
|
8
|
-
const parsed = JSON.parse(jsonString);
|
|
9
|
-
if (validator(parsed)) {
|
|
10
|
-
return parsed;
|
|
11
|
-
}
|
|
12
|
-
console.warn("[Validation] JSON validation failed");
|
|
13
|
-
return null;
|
|
14
|
-
} catch (error) {
|
|
15
|
-
console.error("[Validation] JSON parse error:", error);
|
|
16
|
-
return null;
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
function isValidAccountData(data) {
|
|
20
|
-
return typeof data === "object" && data !== null && typeof data.homeAccountId === "string" && data.homeAccountId.length > 0 && typeof data.username === "string" && data.username.length > 0 && (data.name === void 0 || typeof data.name === "string");
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
// src/utils/getServerSession.ts
|
|
24
|
-
async function getServerSession() {
|
|
25
|
-
try {
|
|
26
|
-
const cookieStore = await cookies();
|
|
27
|
-
const headersList = await headers();
|
|
28
|
-
const msalAccount = cookieStore.get("msal.account");
|
|
29
|
-
const msalToken = cookieStore.get("msal.token");
|
|
30
|
-
if (msalAccount?.value) {
|
|
31
|
-
const accountData = safeJsonParse(
|
|
32
|
-
msalAccount.value,
|
|
33
|
-
isValidAccountData
|
|
34
|
-
);
|
|
35
|
-
if (accountData) {
|
|
36
|
-
return {
|
|
37
|
-
isAuthenticated: true,
|
|
38
|
-
accountId: accountData.homeAccountId,
|
|
39
|
-
username: accountData.username,
|
|
40
|
-
accessToken: msalToken?.value
|
|
41
|
-
};
|
|
42
|
-
} else {
|
|
43
|
-
console.warn("[ServerSession] Invalid account data in cookie");
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
const authHeader = headersList.get("x-msal-authenticated");
|
|
47
|
-
if (authHeader === "true") {
|
|
48
|
-
const username = headersList.get("x-msal-username");
|
|
49
|
-
return {
|
|
50
|
-
isAuthenticated: true,
|
|
51
|
-
username: username || void 0
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
return {
|
|
55
|
-
isAuthenticated: false
|
|
56
|
-
};
|
|
57
|
-
} catch (error) {
|
|
58
|
-
console.error("[ServerSession] Error reading session:", error);
|
|
59
|
-
return {
|
|
60
|
-
isAuthenticated: false
|
|
61
|
-
};
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
async function setServerSessionCookie(account, accessToken) {
|
|
65
|
-
try {
|
|
66
|
-
const accountData = {
|
|
67
|
-
homeAccountId: account.homeAccountId,
|
|
68
|
-
username: account.username,
|
|
69
|
-
name: account.name
|
|
70
|
-
};
|
|
71
|
-
await fetch("/api/auth/session", {
|
|
72
|
-
method: "POST",
|
|
73
|
-
headers: {
|
|
74
|
-
"Content-Type": "application/json"
|
|
75
|
-
},
|
|
76
|
-
body: JSON.stringify({
|
|
77
|
-
account: accountData,
|
|
78
|
-
token: accessToken
|
|
79
|
-
})
|
|
80
|
-
});
|
|
81
|
-
} catch (error) {
|
|
82
|
-
console.error("[ServerSession] Failed to set session cookie:", error);
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
export { getServerSession, setServerSessionCookie };
|
|
87
|
-
//# sourceMappingURL=server.mjs.map
|
|
88
|
-
//# sourceMappingURL=server.mjs.map
|
|
1
|
+
import {cookies,headers}from'next/headers';function o(e,r){try{let n=JSON.parse(e);return r(n)?n:(console.warn("[Validation] JSON validation failed"),null)}catch(n){return console.error("[Validation] JSON parse error:",n),null}}function s(e){return typeof e=="object"&&e!==null&&typeof e.homeAccountId=="string"&&e.homeAccountId.length>0&&typeof e.username=="string"&&e.username.length>0&&(e.name===void 0||typeof e.name=="string")}async function u(){try{let e=await cookies(),r=await headers(),n=e.get("msal.account"),a=e.get("msal.token");if(n?.value){let t=o(n.value,s);if(t)return {isAuthenticated:!0,accountId:t.homeAccountId,username:t.username,accessToken:a?.value};console.warn("[ServerSession] Invalid account data in cookie");}return r.get("x-msal-authenticated")==="true"?{isAuthenticated:!0,username:r.get("x-msal-username")||void 0}:{isAuthenticated:!1}}catch(e){return console.error("[ServerSession] Error reading session:",e),{isAuthenticated:false}}}async function l(e,r){try{let n={homeAccountId:e.homeAccountId,username:e.username,name:e.name};await fetch("/api/auth/session",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({account:n,token:r})});}catch(n){console.error("[ServerSession] Failed to set session cookie:",n);}}export{u as getServerSession,l as setServerSessionCookie};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
{
|
|
1
|
+
{
|
|
2
2
|
"name": "@chemmangat/msal-next",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"description": "Production-grade MSAL authentication package for Next.js App Router with minimal boilerplate",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -74,4 +74,4 @@
|
|
|
74
74
|
"typescript": "^5.3.0",
|
|
75
75
|
"vitest": "^1.0.0"
|
|
76
76
|
}
|
|
77
|
-
}
|
|
77
|
+
}
|
package/dist/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/utils/validation.ts","../src/utils/createMsalConfig.ts","../src/components/MsalAuthProvider.tsx","../src/hooks/useMsalAuth.ts","../src/components/MicrosoftSignInButton.tsx","../src/components/SignOutButton.tsx","../src/hooks/useGraphApi.ts","../src/hooks/useUserProfile.ts","../src/components/UserAvatar.tsx","../src/components/AuthStatus.tsx","../src/components/AuthGuard.tsx","../src/components/ErrorBoundary.tsx","../src/hooks/useRoles.ts","../src/utils/withAuth.tsx","../src/utils/tokenRetry.ts","../src/utils/debugLogger.ts","../src/middleware/createAuthMiddleware.ts"],"names":["LogLevel","useState","useRef","useEffect","PublicClientApplication","EventType","jsx","Fragment","MsalProvider","useMsal","useAccount","useMemo","useCallback","InteractionStatus","jsxs","MicrosoftLogo","error","displayName","Component","CACHE_DURATION","MAX_CACHE_SIZE","enforceCacheLimit","NextResponse"],"mappings":"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","file":"index.js","sourcesContent":["/**\r\n * Security utilities for input validation and sanitization\r\n */\r\n\r\n/**\r\n * Validate account data structure from cookie\r\n */\r\nexport interface ValidatedAccountData {\r\n homeAccountId: string;\r\n username: string;\r\n name?: string;\r\n}\r\n\r\n/**\r\n * Safely parse and validate JSON from untrusted sources\r\n */\r\nexport function safeJsonParse<T>(\r\n jsonString: string,\r\n validator: (data: any) => data is T\r\n): T | null {\r\n try {\r\n const parsed = JSON.parse(jsonString);\r\n if (validator(parsed)) {\r\n return parsed;\r\n }\r\n console.warn('[Validation] JSON validation failed');\r\n return null;\r\n } catch (error) {\r\n console.error('[Validation] JSON parse error:', error);\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * Validate account data structure\r\n */\r\nexport function isValidAccountData(data: any): data is ValidatedAccountData {\r\n return (\r\n typeof data === 'object' &&\r\n data !== null &&\r\n typeof data.homeAccountId === 'string' &&\r\n data.homeAccountId.length > 0 &&\r\n typeof data.username === 'string' &&\r\n data.username.length > 0 &&\r\n (data.name === undefined || typeof data.name === 'string')\r\n );\r\n}\r\n\r\n/**\r\n * Sanitize error messages to prevent information disclosure\r\n */\r\nexport function sanitizeError(error: unknown): string {\r\n if (error instanceof Error) {\r\n // Remove sensitive information from error messages\r\n const message = error.message;\r\n \r\n // Remove potential tokens or secrets (anything that looks like a JWT or long hex string)\r\n const sanitized = message\r\n .replace(/[A-Za-z0-9_-]{20,}\\.[A-Za-z0-9_-]{20,}\\.[A-Za-z0-9_-]{20,}/g, '[TOKEN_REDACTED]')\r\n .replace(/[a-f0-9]{32,}/gi, '[SECRET_REDACTED]')\r\n .replace(/Bearer\\s+[^\\s]+/gi, 'Bearer [REDACTED]');\r\n \r\n return sanitized;\r\n }\r\n \r\n return 'An unexpected error occurred';\r\n}\r\n\r\n/**\r\n * Validate redirect URI to prevent open redirect vulnerabilities\r\n */\r\nexport function isValidRedirectUri(uri: string, allowedOrigins: string[]): boolean {\r\n try {\r\n const url = new URL(uri);\r\n \r\n // Check if the origin is in the allowed list\r\n return allowedOrigins.some(allowed => {\r\n const allowedUrl = new URL(allowed);\r\n return url.origin === allowedUrl.origin;\r\n });\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * Validate scope strings to prevent injection\r\n */\r\nexport function isValidScope(scope: string): boolean {\r\n // Scopes should only contain alphanumeric characters, dots, hyphens, and underscores\r\n return /^[a-zA-Z0-9._-]+$/.test(scope);\r\n}\r\n\r\n/**\r\n * Validate array of scopes\r\n */\r\nexport function validateScopes(scopes: string[]): boolean {\r\n return Array.isArray(scopes) && scopes.every(isValidScope);\r\n}\r\n","import { Configuration, LogLevel } from '@azure/msal-browser';\r\nimport { MsalAuthConfig } from '../types';\r\nimport { isValidRedirectUri } from './validation';\r\n\r\nexport function createMsalConfig(config: MsalAuthConfig): Configuration {\r\n // If custom config provided, use it\r\n if (config.msalConfig) {\r\n return config.msalConfig;\r\n }\r\n\r\n const {\r\n clientId,\r\n tenantId,\r\n authorityType = 'common',\r\n redirectUri,\r\n postLogoutRedirectUri,\r\n cacheLocation = 'sessionStorage',\r\n storeAuthStateInCookie = false,\r\n navigateToLoginRequestUrl = true,\r\n enableLogging = false,\r\n loggerCallback,\r\n allowedRedirectUris,\r\n } = config;\r\n\r\n if (!clientId) {\r\n throw new Error('@chemmangat/msal-next: clientId is required');\r\n }\r\n\r\n // Build authority URL\r\n const getAuthority = (): string => {\r\n if (authorityType === 'tenant') {\r\n if (!tenantId) {\r\n throw new Error('@chemmangat/msal-next: tenantId is required when authorityType is \"tenant\"');\r\n }\r\n return `https://login.microsoftonline.com/${tenantId}`;\r\n }\r\n return `https://login.microsoftonline.com/${authorityType}`;\r\n };\r\n\r\n // Default redirect URI\r\n const defaultRedirectUri = typeof window !== 'undefined' ? window.location.origin : 'http://localhost:3000';\r\n const finalRedirectUri = redirectUri || defaultRedirectUri;\r\n\r\n // Validate redirect URIs if allowedRedirectUris is provided\r\n if (allowedRedirectUris && allowedRedirectUris.length > 0) {\r\n if (!isValidRedirectUri(finalRedirectUri, allowedRedirectUris)) {\r\n throw new Error(\r\n `@chemmangat/msal-next: redirectUri \"${finalRedirectUri}\" is not in the allowed list`\r\n );\r\n }\r\n\r\n const finalPostLogoutUri = postLogoutRedirectUri || finalRedirectUri;\r\n if (!isValidRedirectUri(finalPostLogoutUri, allowedRedirectUris)) {\r\n throw new Error(\r\n `@chemmangat/msal-next: postLogoutRedirectUri \"${finalPostLogoutUri}\" is not in the allowed list`\r\n );\r\n }\r\n }\r\n\r\n const msalConfig: Configuration = {\r\n auth: {\r\n clientId,\r\n authority: getAuthority(),\r\n redirectUri: finalRedirectUri,\r\n postLogoutRedirectUri: postLogoutRedirectUri || finalRedirectUri,\r\n navigateToLoginRequestUrl,\r\n },\r\n cache: {\r\n cacheLocation,\r\n storeAuthStateInCookie,\r\n },\r\n system: {\r\n loggerOptions: {\r\n loggerCallback: loggerCallback || ((level: LogLevel, message: string, containsPii: boolean) => {\r\n if (containsPii || !enableLogging) return;\r\n \r\n switch (level) {\r\n case LogLevel.Error:\r\n console.error('[MSAL]', message);\r\n break;\r\n case LogLevel.Warning:\r\n console.warn('[MSAL]', message);\r\n break;\r\n case LogLevel.Info:\r\n console.info('[MSAL]', message);\r\n break;\r\n case LogLevel.Verbose:\r\n console.debug('[MSAL]', message);\r\n break;\r\n }\r\n }),\r\n logLevel: enableLogging ? LogLevel.Verbose : LogLevel.Error,\r\n },\r\n },\r\n };\r\n\r\n return msalConfig;\r\n}\r\n","'use client';\r\n\r\nimport { MsalProvider } from '@azure/msal-react';\r\nimport { PublicClientApplication, EventType, EventMessage, AuthenticationResult } from '@azure/msal-browser';\r\nimport { useEffect, useState, useRef } from 'react';\r\nimport { MsalAuthProviderProps } from '../types';\r\nimport { createMsalConfig } from '../utils/createMsalConfig';\r\n\r\n// Module-level variable to store the MSAL instance\r\nlet globalMsalInstance: PublicClientApplication | null = null;\r\n\r\n/**\r\n * Get the current MSAL instance\r\n * @returns The MSAL instance or null if not initialized\r\n */\r\nexport function getMsalInstance(): PublicClientApplication | null {\r\n return globalMsalInstance;\r\n}\r\n\r\nexport function MsalAuthProvider({ children, loadingComponent, onInitialized, ...config }: MsalAuthProviderProps) {\r\n const [msalInstance, setMsalInstance] = useState<PublicClientApplication | null>(null);\r\n const instanceRef = useRef<PublicClientApplication | null>(null);\r\n\r\n useEffect(() => {\r\n // SSR safety guard\r\n if (typeof window === 'undefined') {\r\n return;\r\n }\r\n\r\n // Prevent multiple initializations\r\n if (instanceRef.current) {\r\n return;\r\n }\r\n\r\n const initializeMsal = async () => {\r\n try {\r\n const msalConfig = createMsalConfig(config);\r\n const instance = new PublicClientApplication(msalConfig);\r\n \r\n await instance.initialize();\r\n\r\n // Handle redirect promise\r\n const response = await instance.handleRedirectPromise();\r\n if (response && config.enableLogging) {\r\n console.log('[MSAL] Redirect authentication successful');\r\n }\r\n\r\n // Set up event callbacks\r\n const enableLogging = config.enableLogging || false;\r\n instance.addEventCallback((event: EventMessage) => {\r\n if (event.eventType === EventType.LOGIN_SUCCESS) {\r\n if (enableLogging) {\r\n const payload = event.payload as AuthenticationResult;\r\n console.log('[MSAL] Login successful:', payload.account?.username);\r\n }\r\n }\r\n \r\n if (event.eventType === EventType.LOGIN_FAILURE) {\r\n // Always log errors regardless of enableLogging\r\n console.error('[MSAL] Login failed:', event.error);\r\n }\r\n\r\n if (event.eventType === EventType.LOGOUT_SUCCESS) {\r\n if (enableLogging) {\r\n console.log('[MSAL] Logout successful');\r\n }\r\n }\r\n });\r\n\r\n instanceRef.current = instance;\r\n globalMsalInstance = instance;\r\n setMsalInstance(instance);\r\n\r\n // Call onInitialized callback if provided\r\n if (onInitialized) {\r\n onInitialized(instance);\r\n }\r\n } catch (error) {\r\n console.error('[MSAL] Initialization failed:', error);\r\n throw error;\r\n }\r\n };\r\n\r\n initializeMsal();\r\n }, []); // Empty dependency array - only initialize once\r\n\r\n // SSR safety guard - render children or loading component on server\r\n if (typeof window === 'undefined') {\r\n return <>{loadingComponent || <div>Loading authentication...</div>}</>;\r\n }\r\n\r\n if (!msalInstance) {\r\n return <>{loadingComponent || <div>Loading authentication...</div>}</>;\r\n }\r\n\r\n return <MsalProvider instance={msalInstance}>{children}</MsalProvider>;\r\n}\r\n","'use client';\r\n\r\nimport { useMsal, useAccount } from '@azure/msal-react';\r\nimport { AccountInfo, InteractionStatus, PopupRequest, RedirectRequest, SilentRequest } from '@azure/msal-browser';\r\nimport { useCallback, useMemo, useRef } from 'react';\r\n\r\nexport interface UseMsalAuthReturn {\r\n /**\r\n * Current authenticated account\r\n */\r\n account: AccountInfo | null;\r\n\r\n /**\r\n * All accounts in the cache\r\n */\r\n accounts: AccountInfo[];\r\n\r\n /**\r\n * Whether user is authenticated\r\n */\r\n isAuthenticated: boolean;\r\n\r\n /**\r\n * Whether MSAL is currently performing an interaction\r\n */\r\n inProgress: boolean;\r\n\r\n /**\r\n * Login using popup\r\n */\r\n loginPopup: (scopes?: string[]) => Promise<void>;\r\n\r\n /**\r\n * Login using redirect\r\n */\r\n loginRedirect: (scopes?: string[]) => Promise<void>;\r\n\r\n /**\r\n * Logout using popup\r\n */\r\n logoutPopup: () => Promise<void>;\r\n\r\n /**\r\n * Logout using redirect\r\n */\r\n logoutRedirect: () => Promise<void>;\r\n\r\n /**\r\n * Acquire access token silently (with fallback to popup)\r\n */\r\n acquireToken: (scopes: string[]) => Promise<string>;\r\n\r\n /**\r\n * Acquire access token silently only (no fallback)\r\n */\r\n acquireTokenSilent: (scopes: string[]) => Promise<string>;\r\n\r\n /**\r\n * Acquire access token using popup\r\n */\r\n acquireTokenPopup: (scopes: string[]) => Promise<string>;\r\n\r\n /**\r\n * Acquire access token using redirect\r\n */\r\n acquireTokenRedirect: (scopes: string[]) => Promise<void>;\r\n\r\n /**\r\n * Clear MSAL session without triggering Microsoft logout\r\n */\r\n clearSession: () => Promise<void>;\r\n}\r\n\r\n// Request deduplication map to prevent race conditions\r\nconst pendingTokenRequests = new Map<string, Promise<string>>();\r\n\r\nexport function useMsalAuth(defaultScopes: string[] = ['User.Read']): UseMsalAuthReturn {\r\n const { instance, accounts, inProgress } = useMsal();\r\n const account = useAccount(accounts[0] || null);\r\n const popupInProgressRef = useRef(false);\r\n\r\n const isAuthenticated = useMemo(() => accounts.length > 0, [accounts]);\r\n\r\n const loginPopup = useCallback(\r\n async (scopes: string[] = defaultScopes) => {\r\n try {\r\n const request: PopupRequest = {\r\n scopes,\r\n prompt: 'select_account',\r\n };\r\n await instance.loginPopup(request);\r\n } catch (error) {\r\n console.error('[MSAL] Login popup failed:', error);\r\n throw error;\r\n }\r\n },\r\n [instance, defaultScopes]\r\n );\r\n\r\n const loginRedirect = useCallback(\r\n async (scopes: string[] = defaultScopes) => {\r\n try {\r\n const request: RedirectRequest = {\r\n scopes,\r\n prompt: 'select_account',\r\n };\r\n await instance.loginRedirect(request);\r\n } catch (error) {\r\n console.error('[MSAL] Login redirect failed:', error);\r\n throw error;\r\n }\r\n },\r\n [instance, defaultScopes]\r\n );\r\n\r\n const logoutPopup = useCallback(async () => {\r\n try {\r\n await instance.logoutPopup({\r\n account: account || undefined,\r\n });\r\n } catch (error) {\r\n console.error('[MSAL] Logout popup failed:', error);\r\n throw error;\r\n }\r\n }, [instance, account]);\r\n\r\n const logoutRedirect = useCallback(async () => {\r\n try {\r\n await instance.logoutRedirect({\r\n account: account || undefined,\r\n });\r\n } catch (error) {\r\n console.error('[MSAL] Logout redirect failed:', error);\r\n throw error;\r\n }\r\n }, [instance, account]);\r\n\r\n const acquireTokenSilent = useCallback(\r\n async (scopes: string[] = defaultScopes): Promise<string> => {\r\n if (!account) {\r\n throw new Error('[MSAL] No active account. Please login first.');\r\n }\r\n\r\n try {\r\n const request: SilentRequest = {\r\n scopes,\r\n account,\r\n forceRefresh: false,\r\n };\r\n const response = await instance.acquireTokenSilent(request);\r\n return response.accessToken;\r\n } catch (error) {\r\n console.error('[MSAL] Silent token acquisition failed:', error);\r\n throw error;\r\n }\r\n },\r\n [instance, account, defaultScopes]\r\n );\r\n\r\n const acquireTokenPopup = useCallback(\r\n async (scopes: string[] = defaultScopes): Promise<string> => {\r\n if (!account) {\r\n throw new Error('[MSAL] No active account. Please login first.');\r\n }\r\n\r\n // Prevent multiple concurrent popup requests\r\n if (popupInProgressRef.current) {\r\n throw new Error('[MSAL] Popup already in progress. Please wait.');\r\n }\r\n\r\n try {\r\n popupInProgressRef.current = true;\r\n const request: PopupRequest = {\r\n scopes,\r\n account,\r\n };\r\n const response = await instance.acquireTokenPopup(request);\r\n return response.accessToken;\r\n } catch (error) {\r\n console.error('[MSAL] Token popup acquisition failed:', error);\r\n throw error;\r\n } finally {\r\n popupInProgressRef.current = false;\r\n }\r\n },\r\n [instance, account, defaultScopes]\r\n );\r\n\r\n const acquireTokenRedirect = useCallback(\r\n async (scopes: string[] = defaultScopes): Promise<void> => {\r\n if (!account) {\r\n throw new Error('[MSAL] No active account. Please login first.');\r\n }\r\n\r\n try {\r\n const request: RedirectRequest = {\r\n scopes,\r\n account,\r\n };\r\n await instance.acquireTokenRedirect(request);\r\n } catch (error) {\r\n console.error('[MSAL] Token redirect acquisition failed:', error);\r\n throw error;\r\n }\r\n },\r\n [instance, account, defaultScopes]\r\n );\r\n\r\n const acquireToken = useCallback(\r\n async (scopes: string[] = defaultScopes): Promise<string> => {\r\n // Create a unique key for request deduplication\r\n const requestKey = `${account?.homeAccountId || 'anonymous'}-${scopes.sort().join(',')}`;\r\n\r\n // Check if there's already a pending request for these scopes\r\n const pendingRequest = pendingTokenRequests.get(requestKey);\r\n if (pendingRequest) {\r\n return pendingRequest;\r\n }\r\n\r\n // Create new request\r\n const tokenRequest = (async () => {\r\n try {\r\n return await acquireTokenSilent(scopes);\r\n } catch (error) {\r\n console.warn('[MSAL] Silent token acquisition failed, falling back to popup');\r\n return await acquireTokenPopup(scopes);\r\n } finally {\r\n // Clean up pending request\r\n pendingTokenRequests.delete(requestKey);\r\n }\r\n })();\r\n\r\n // Store pending request\r\n pendingTokenRequests.set(requestKey, tokenRequest);\r\n\r\n return tokenRequest;\r\n },\r\n [acquireTokenSilent, acquireTokenPopup, defaultScopes, account]\r\n );\r\n\r\n const clearSession = useCallback(async () => {\r\n instance.setActiveAccount(null);\r\n await instance.clearCache();\r\n }, [instance]);\r\n\r\n return {\r\n account,\r\n accounts,\r\n isAuthenticated,\r\n inProgress: inProgress !== InteractionStatus.None,\r\n loginPopup,\r\n loginRedirect,\r\n logoutPopup,\r\n logoutRedirect,\r\n acquireToken,\r\n acquireTokenSilent,\r\n acquireTokenPopup,\r\n acquireTokenRedirect,\r\n clearSession,\r\n };\r\n}\r\n","'use client';\r\n\r\nimport { useMsalAuth } from '../hooks/useMsalAuth';\r\nimport { CSSProperties } from 'react';\r\n\r\nexport interface MicrosoftSignInButtonProps {\r\n /**\r\n * Button text\r\n * @default 'Sign in with Microsoft'\r\n */\r\n text?: string;\r\n \r\n /**\r\n * Button variant\r\n * @default 'dark'\r\n */\r\n variant?: 'dark' | 'light';\r\n \r\n /**\r\n * Button size\r\n * @default 'medium'\r\n */\r\n size?: 'small' | 'medium' | 'large';\r\n \r\n /**\r\n * Use redirect flow instead of popup\r\n * @default false\r\n */\r\n useRedirect?: boolean;\r\n \r\n /**\r\n * Scopes to request\r\n */\r\n scopes?: string[];\r\n \r\n /**\r\n * Custom className\r\n */\r\n className?: string;\r\n \r\n /**\r\n * Custom styles\r\n */\r\n style?: CSSProperties;\r\n \r\n /**\r\n * Callback on successful login\r\n */\r\n onSuccess?: () => void;\r\n \r\n /**\r\n * Callback on error\r\n */\r\n onError?: (error: Error) => void;\r\n}\r\n\r\nexport function MicrosoftSignInButton({\r\n text = 'Sign in with Microsoft',\r\n variant = 'dark',\r\n size = 'medium',\r\n useRedirect = false,\r\n scopes,\r\n className = '',\r\n style,\r\n onSuccess,\r\n onError,\r\n}: MicrosoftSignInButtonProps) {\r\n const { loginPopup, loginRedirect, inProgress } = useMsalAuth();\r\n\r\n const handleClick = async () => {\r\n try {\r\n if (useRedirect) {\r\n await loginRedirect(scopes);\r\n } else {\r\n await loginPopup(scopes);\r\n }\r\n onSuccess?.();\r\n } catch (error) {\r\n onError?.(error as Error);\r\n }\r\n };\r\n\r\n const sizeStyles = {\r\n small: {\r\n padding: '8px 16px',\r\n fontSize: '14px',\r\n height: '36px',\r\n },\r\n medium: {\r\n padding: '10px 20px',\r\n fontSize: '15px',\r\n height: '41px',\r\n },\r\n large: {\r\n padding: '12px 24px',\r\n fontSize: '16px',\r\n height: '48px',\r\n },\r\n };\r\n\r\n const variantStyles = {\r\n dark: {\r\n backgroundColor: '#2F2F2F',\r\n color: '#FFFFFF',\r\n border: '1px solid #8C8C8C',\r\n },\r\n light: {\r\n backgroundColor: '#FFFFFF',\r\n color: '#5E5E5E',\r\n border: '1px solid #8C8C8C',\r\n },\r\n };\r\n\r\n const baseStyles: CSSProperties = {\r\n display: 'inline-flex',\r\n alignItems: 'center',\r\n justifyContent: 'center',\r\n gap: '12px',\r\n fontFamily: '\"Segoe UI\", Tahoma, Geneva, Verdana, sans-serif',\r\n fontWeight: 600,\r\n borderRadius: '2px',\r\n cursor: inProgress ? 'not-allowed' : 'pointer',\r\n transition: 'all 0.2s ease',\r\n opacity: inProgress ? 0.6 : 1,\r\n ...variantStyles[variant],\r\n ...sizeStyles[size],\r\n ...style,\r\n };\r\n\r\n return (\r\n <button\r\n onClick={handleClick}\r\n disabled={inProgress}\r\n className={className}\r\n style={baseStyles}\r\n aria-label={text}\r\n >\r\n <MicrosoftLogo />\r\n <span>{text}</span>\r\n </button>\r\n );\r\n}\r\n\r\nfunction MicrosoftLogo() {\r\n return (\r\n <svg width=\"21\" height=\"21\" viewBox=\"0 0 21 21\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\r\n <rect width=\"10\" height=\"10\" fill=\"#F25022\" />\r\n <rect x=\"11\" width=\"10\" height=\"10\" fill=\"#7FBA00\" />\r\n <rect y=\"11\" width=\"10\" height=\"10\" fill=\"#00A4EF\" />\r\n <rect x=\"11\" y=\"11\" width=\"10\" height=\"10\" fill=\"#FFB900\" />\r\n </svg>\r\n );\r\n}\r\n","'use client';\r\n\r\nimport { useMsalAuth } from '../hooks/useMsalAuth';\r\nimport { CSSProperties } from 'react';\r\n\r\nexport interface SignOutButtonProps {\r\n /**\r\n * Button text\r\n * @default 'Sign out'\r\n */\r\n text?: string;\r\n \r\n /**\r\n * Button variant\r\n * @default 'dark'\r\n */\r\n variant?: 'dark' | 'light';\r\n \r\n /**\r\n * Button size\r\n * @default 'medium'\r\n */\r\n size?: 'small' | 'medium' | 'large';\r\n \r\n /**\r\n * Use redirect flow instead of popup\r\n * @default false\r\n */\r\n useRedirect?: boolean;\r\n \r\n /**\r\n * Custom className\r\n */\r\n className?: string;\r\n \r\n /**\r\n * Custom styles\r\n */\r\n style?: CSSProperties;\r\n \r\n /**\r\n * Callback on successful logout\r\n */\r\n onSuccess?: () => void;\r\n \r\n /**\r\n * Callback on error\r\n */\r\n onError?: (error: Error) => void;\r\n}\r\n\r\n/**\r\n * SignOutButton component with Microsoft branding\r\n * \r\n * @example\r\n * ```tsx\r\n * <SignOutButton variant=\"light\" />\r\n * ```\r\n */\r\nexport function SignOutButton({\r\n text = 'Sign out',\r\n variant = 'dark',\r\n size = 'medium',\r\n useRedirect = false,\r\n className = '',\r\n style,\r\n onSuccess,\r\n onError,\r\n}: SignOutButtonProps) {\r\n const { logoutPopup, logoutRedirect, inProgress } = useMsalAuth();\r\n\r\n const handleClick = async () => {\r\n try {\r\n if (useRedirect) {\r\n await logoutRedirect();\r\n } else {\r\n await logoutPopup();\r\n }\r\n onSuccess?.();\r\n } catch (error) {\r\n onError?.(error as Error);\r\n }\r\n };\r\n\r\n const sizeStyles = {\r\n small: {\r\n padding: '8px 16px',\r\n fontSize: '14px',\r\n height: '36px',\r\n },\r\n medium: {\r\n padding: '10px 20px',\r\n fontSize: '15px',\r\n height: '41px',\r\n },\r\n large: {\r\n padding: '12px 24px',\r\n fontSize: '16px',\r\n height: '48px',\r\n },\r\n };\r\n\r\n const variantStyles = {\r\n dark: {\r\n backgroundColor: '#2F2F2F',\r\n color: '#FFFFFF',\r\n border: '1px solid #8C8C8C',\r\n },\r\n light: {\r\n backgroundColor: '#FFFFFF',\r\n color: '#5E5E5E',\r\n border: '1px solid #8C8C8C',\r\n },\r\n };\r\n\r\n const baseStyles: CSSProperties = {\r\n display: 'inline-flex',\r\n alignItems: 'center',\r\n justifyContent: 'center',\r\n gap: '12px',\r\n fontFamily: '\"Segoe UI\", Tahoma, Geneva, Verdana, sans-serif',\r\n fontWeight: 600,\r\n borderRadius: '2px',\r\n cursor: inProgress ? 'not-allowed' : 'pointer',\r\n transition: 'all 0.2s ease',\r\n opacity: inProgress ? 0.6 : 1,\r\n ...variantStyles[variant],\r\n ...sizeStyles[size],\r\n ...style,\r\n };\r\n\r\n return (\r\n <button\r\n onClick={handleClick}\r\n disabled={inProgress}\r\n className={className}\r\n style={baseStyles}\r\n aria-label={text}\r\n >\r\n <MicrosoftLogo />\r\n <span>{text}</span>\r\n </button>\r\n );\r\n}\r\n\r\nfunction MicrosoftLogo() {\r\n return (\r\n <svg width=\"21\" height=\"21\" viewBox=\"0 0 21 21\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\r\n <rect width=\"10\" height=\"10\" fill=\"#F25022\" />\r\n <rect x=\"11\" width=\"10\" height=\"10\" fill=\"#7FBA00\" />\r\n <rect y=\"11\" width=\"10\" height=\"10\" fill=\"#00A4EF\" />\r\n <rect x=\"11\" y=\"11\" width=\"10\" height=\"10\" fill=\"#FFB900\" />\r\n </svg>\r\n );\r\n}\r\n","'use client';\r\n\r\nimport { useCallback } from 'react';\r\nimport { useMsalAuth } from './useMsalAuth';\r\nimport { sanitizeError } from '../utils/validation';\r\n\r\nexport interface GraphApiOptions extends RequestInit {\r\n /**\r\n * Scopes required for the API call\r\n * @default ['User.Read']\r\n */\r\n scopes?: string[];\r\n\r\n /**\r\n * API version\r\n * @default 'v1.0'\r\n */\r\n version?: 'v1.0' | 'beta';\r\n\r\n /**\r\n * Enable debug logging\r\n * @default false\r\n */\r\n debug?: boolean;\r\n}\r\n\r\nexport interface UseGraphApiReturn {\r\n /**\r\n * Make a GET request to MS Graph API\r\n */\r\n get: <T = any>(endpoint: string, options?: GraphApiOptions) => Promise<T>;\r\n\r\n /**\r\n * Make a POST request to MS Graph API\r\n */\r\n post: <T = any>(endpoint: string, body?: any, options?: GraphApiOptions) => Promise<T>;\r\n\r\n /**\r\n * Make a PUT request to MS Graph API\r\n */\r\n put: <T = any>(endpoint: string, body?: any, options?: GraphApiOptions) => Promise<T>;\r\n\r\n /**\r\n * Make a PATCH request to MS Graph API\r\n */\r\n patch: <T = any>(endpoint: string, body?: any, options?: GraphApiOptions) => Promise<T>;\r\n\r\n /**\r\n * Make a DELETE request to MS Graph API\r\n */\r\n delete: <T = any>(endpoint: string, options?: GraphApiOptions) => Promise<T>;\r\n\r\n /**\r\n * Make a custom request to MS Graph API\r\n */\r\n request: <T = any>(endpoint: string, options?: GraphApiOptions) => Promise<T>;\r\n}\r\n\r\n/**\r\n * Hook for making authenticated requests to MS Graph API\r\n * \r\n * @example\r\n * ```tsx\r\n * const graph = useGraphApi();\r\n * const user = await graph.get('/me');\r\n * ```\r\n */\r\nexport function useGraphApi(): UseGraphApiReturn {\r\n const { acquireToken } = useMsalAuth();\r\n\r\n const request = useCallback(\r\n async <T = any>(endpoint: string, options: GraphApiOptions = {}): Promise<T> => {\r\n const {\r\n scopes = ['User.Read'],\r\n version = 'v1.0',\r\n debug = false,\r\n ...fetchOptions\r\n } = options;\r\n\r\n try {\r\n // Acquire access token\r\n const token = await acquireToken(scopes);\r\n\r\n // Build URL\r\n const baseUrl = `https://graph.microsoft.com/${version}`;\r\n const url = endpoint.startsWith('http') ? endpoint : `${baseUrl}${endpoint.startsWith('/') ? endpoint : `/${endpoint}`}`;\r\n\r\n if (debug) {\r\n console.log('[GraphAPI] Request:', { url, method: fetchOptions.method || 'GET' });\r\n }\r\n\r\n // Make request\r\n const response = await fetch(url, {\r\n ...fetchOptions,\r\n headers: {\r\n 'Authorization': `Bearer ${token}`,\r\n 'Content-Type': 'application/json',\r\n ...fetchOptions.headers,\r\n },\r\n });\r\n\r\n if (!response.ok) {\r\n const errorText = await response.text();\r\n const errorMessage = `Graph API error (${response.status}): ${errorText}`;\r\n throw new Error(errorMessage);\r\n }\r\n\r\n // Handle empty responses\r\n if (response.status === 204 || response.headers.get('content-length') === '0') {\r\n return null as T;\r\n }\r\n\r\n const data = await response.json();\r\n\r\n if (debug) {\r\n console.log('[GraphAPI] Response:', data);\r\n }\r\n\r\n return data as T;\r\n } catch (error) {\r\n const sanitizedMessage = sanitizeError(error);\r\n console.error('[GraphAPI] Request failed:', sanitizedMessage);\r\n throw new Error(sanitizedMessage);\r\n }\r\n },\r\n [acquireToken]\r\n );\r\n\r\n const get = useCallback(\r\n <T = any>(endpoint: string, options: GraphApiOptions = {}): Promise<T> => {\r\n return request<T>(endpoint, { ...options, method: 'GET' });\r\n },\r\n [request]\r\n );\r\n\r\n const post = useCallback(\r\n <T = any>(endpoint: string, body?: any, options: GraphApiOptions = {}): Promise<T> => {\r\n return request<T>(endpoint, {\r\n ...options,\r\n method: 'POST',\r\n body: body ? JSON.stringify(body) : undefined,\r\n });\r\n },\r\n [request]\r\n );\r\n\r\n const put = useCallback(\r\n <T = any>(endpoint: string, body?: any, options: GraphApiOptions = {}): Promise<T> => {\r\n return request<T>(endpoint, {\r\n ...options,\r\n method: 'PUT',\r\n body: body ? JSON.stringify(body) : undefined,\r\n });\r\n },\r\n [request]\r\n );\r\n\r\n const patch = useCallback(\r\n <T = any>(endpoint: string, body?: any, options: GraphApiOptions = {}): Promise<T> => {\r\n return request<T>(endpoint, {\r\n ...options,\r\n method: 'PATCH',\r\n body: body ? JSON.stringify(body) : undefined,\r\n });\r\n },\r\n [request]\r\n );\r\n\r\n const deleteRequest = useCallback(\r\n <T = any>(endpoint: string, options: GraphApiOptions = {}): Promise<T> => {\r\n return request<T>(endpoint, { ...options, method: 'DELETE' });\r\n },\r\n [request]\r\n );\r\n\r\n return {\r\n get,\r\n post,\r\n put,\r\n patch,\r\n delete: deleteRequest,\r\n request,\r\n };\r\n}\r\n","'use client';\r\n\r\nimport { useState, useEffect, useCallback } from 'react';\r\nimport { useMsalAuth } from './useMsalAuth';\r\nimport { useGraphApi } from './useGraphApi';\r\nimport { sanitizeError } from '../utils/validation';\r\n\r\nexport interface UserProfile {\r\n id: string;\r\n displayName: string;\r\n givenName: string;\r\n surname: string;\r\n userPrincipalName: string;\r\n mail: string;\r\n jobTitle?: string;\r\n officeLocation?: string;\r\n mobilePhone?: string;\r\n businessPhones?: string[];\r\n photo?: string;\r\n}\r\n\r\nexport interface UseUserProfileReturn {\r\n /**\r\n * User profile data\r\n */\r\n profile: UserProfile | null;\r\n\r\n /**\r\n * Whether profile is loading\r\n */\r\n loading: boolean;\r\n\r\n /**\r\n * Error if profile fetch failed\r\n */\r\n error: Error | null;\r\n\r\n /**\r\n * Refetch user profile\r\n */\r\n refetch: () => Promise<void>;\r\n\r\n /**\r\n * Clear cached profile\r\n */\r\n clearCache: () => void;\r\n}\r\n\r\n// Simple in-memory cache with size limit\r\nconst profileCache = new Map<string, { data: UserProfile; timestamp: number }>();\r\nconst CACHE_DURATION = 5 * 60 * 1000; // 5 minutes\r\nconst MAX_CACHE_SIZE = 100; // Prevent memory leaks\r\n\r\n/**\r\n * Enforce cache size limit using LRU strategy\r\n */\r\nfunction enforceCacheLimit(): void {\r\n if (profileCache.size > MAX_CACHE_SIZE) {\r\n // Remove oldest entries\r\n const entries = Array.from(profileCache.entries());\r\n entries.sort((a, b) => a[1].timestamp - b[1].timestamp);\r\n const toRemove = entries.slice(0, profileCache.size - MAX_CACHE_SIZE);\r\n toRemove.forEach(([key]) => {\r\n const cached = profileCache.get(key);\r\n // Revoke blob URL before removing from cache\r\n if (cached?.data.photo) {\r\n URL.revokeObjectURL(cached.data.photo);\r\n }\r\n profileCache.delete(key);\r\n });\r\n }\r\n}\r\n\r\n/**\r\n * Hook for fetching and caching user profile from MS Graph\r\n * \r\n * @example\r\n * ```tsx\r\n * const { profile, loading } = useUserProfile();\r\n * ```\r\n */\r\nexport function useUserProfile(): UseUserProfileReturn {\r\n const { isAuthenticated, account } = useMsalAuth();\r\n const graph = useGraphApi();\r\n const [profile, setProfile] = useState<UserProfile | null>(null);\r\n const [loading, setLoading] = useState(false);\r\n const [error, setError] = useState<Error | null>(null);\r\n\r\n const fetchProfile = useCallback(async () => {\r\n if (!isAuthenticated || !account) {\r\n setProfile(null);\r\n return;\r\n }\r\n\r\n const cacheKey = account.homeAccountId;\r\n\r\n // Check cache\r\n const cached = profileCache.get(cacheKey);\r\n if (cached && Date.now() - cached.timestamp < CACHE_DURATION) {\r\n setProfile(cached.data);\r\n return;\r\n }\r\n\r\n setLoading(true);\r\n setError(null);\r\n\r\n try {\r\n // Fetch user profile\r\n const userData = await graph.get<any>('/me', {\r\n scopes: ['User.Read'],\r\n });\r\n\r\n // Try to fetch user photo\r\n let photoUrl: string | undefined;\r\n try {\r\n const photoBlob = await graph.get<Blob>('/me/photo/$value', {\r\n scopes: ['User.Read'],\r\n headers: {\r\n 'Content-Type': 'image/jpeg',\r\n },\r\n });\r\n\r\n if (photoBlob) {\r\n photoUrl = URL.createObjectURL(photoBlob as any);\r\n }\r\n } catch (photoError) {\r\n // Photo might not exist, that's okay\r\n console.debug('[UserProfile] Photo not available');\r\n }\r\n\r\n const profileData: UserProfile = {\r\n id: userData.id,\r\n displayName: userData.displayName,\r\n givenName: userData.givenName,\r\n surname: userData.surname,\r\n userPrincipalName: userData.userPrincipalName,\r\n mail: userData.mail,\r\n jobTitle: userData.jobTitle,\r\n officeLocation: userData.officeLocation,\r\n mobilePhone: userData.mobilePhone,\r\n businessPhones: userData.businessPhones,\r\n photo: photoUrl,\r\n };\r\n\r\n // Cache the profile\r\n profileCache.set(cacheKey, {\r\n data: profileData,\r\n timestamp: Date.now(),\r\n });\r\n\r\n // Enforce cache size limit\r\n enforceCacheLimit();\r\n\r\n setProfile(profileData);\r\n } catch (err) {\r\n const error = err as Error;\r\n const sanitizedMessage = sanitizeError(error);\r\n const sanitizedError = new Error(sanitizedMessage);\r\n setError(sanitizedError);\r\n console.error('[UserProfile] Failed to fetch profile:', sanitizedMessage);\r\n } finally {\r\n setLoading(false);\r\n }\r\n }, [isAuthenticated, account, graph]);\r\n\r\n const clearCache = useCallback(() => {\r\n if (account) {\r\n const cached = profileCache.get(account.homeAccountId);\r\n // Revoke blob URL before clearing\r\n if (cached?.data.photo) {\r\n URL.revokeObjectURL(cached.data.photo);\r\n }\r\n profileCache.delete(account.homeAccountId);\r\n }\r\n // Revoke current profile photo URL\r\n if (profile?.photo) {\r\n URL.revokeObjectURL(profile.photo);\r\n }\r\n setProfile(null);\r\n }, [account, profile]);\r\n\r\n useEffect(() => {\r\n fetchProfile();\r\n\r\n // Cleanup: revoke blob URLs to prevent memory leaks\r\n return () => {\r\n if (profile?.photo) {\r\n URL.revokeObjectURL(profile.photo);\r\n }\r\n };\r\n }, [fetchProfile]);\r\n\r\n // Cleanup on unmount\r\n useEffect(() => {\r\n return () => {\r\n if (profile?.photo) {\r\n URL.revokeObjectURL(profile.photo);\r\n }\r\n };\r\n }, [profile?.photo]);\r\n\r\n return {\r\n profile,\r\n loading,\r\n error,\r\n refetch: fetchProfile,\r\n clearCache,\r\n };\r\n}\r\n","'use client';\r\n\r\nimport { CSSProperties, useEffect, useState } from 'react';\r\nimport { useUserProfile } from '../hooks/useUserProfile';\r\n\r\nexport interface UserAvatarProps {\r\n /**\r\n * Avatar size in pixels\r\n * @default 40\r\n */\r\n size?: number;\r\n\r\n /**\r\n * Custom className\r\n */\r\n className?: string;\r\n\r\n /**\r\n * Custom styles\r\n */\r\n style?: CSSProperties;\r\n\r\n /**\r\n * Show user name tooltip on hover\r\n * @default true\r\n */\r\n showTooltip?: boolean;\r\n\r\n /**\r\n * Fallback image URL if MS Graph photo fails\r\n */\r\n fallbackImage?: string;\r\n}\r\n\r\n/**\r\n * UserAvatar component that displays user photo from MS Graph with fallback initials\r\n * \r\n * @example\r\n * ```tsx\r\n * <UserAvatar size={48} />\r\n * ```\r\n */\r\nexport function UserAvatar({\r\n size = 40,\r\n className = '',\r\n style,\r\n showTooltip = true,\r\n fallbackImage,\r\n}: UserAvatarProps) {\r\n const { profile, loading } = useUserProfile();\r\n const [photoUrl, setPhotoUrl] = useState<string | null>(null);\r\n const [photoError, setPhotoError] = useState(false);\r\n\r\n useEffect(() => {\r\n if (profile?.photo) {\r\n setPhotoUrl(profile.photo);\r\n }\r\n }, [profile?.photo]);\r\n\r\n const getInitials = () => {\r\n if (!profile) return '?';\r\n \r\n const { givenName, surname, displayName } = profile;\r\n \r\n if (givenName && surname) {\r\n return `${givenName[0]}${surname[0]}`.toUpperCase();\r\n }\r\n \r\n if (displayName) {\r\n const parts = displayName.split(' ');\r\n if (parts.length >= 2) {\r\n return `${parts[0][0]}${parts[parts.length - 1][0]}`.toUpperCase();\r\n }\r\n return displayName.substring(0, 2).toUpperCase();\r\n }\r\n \r\n return '?';\r\n };\r\n\r\n const baseStyles: CSSProperties = {\r\n width: `${size}px`,\r\n height: `${size}px`,\r\n borderRadius: '50%',\r\n display: 'inline-flex',\r\n alignItems: 'center',\r\n justifyContent: 'center',\r\n fontSize: `${size * 0.4}px`,\r\n fontWeight: 600,\r\n fontFamily: '\"Segoe UI\", Tahoma, Geneva, Verdana, sans-serif',\r\n backgroundColor: '#0078D4',\r\n color: '#FFFFFF',\r\n overflow: 'hidden',\r\n userSelect: 'none',\r\n ...style,\r\n };\r\n\r\n const displayName = profile?.displayName || 'User';\r\n\r\n if (loading) {\r\n return (\r\n <div\r\n className={className}\r\n style={{ ...baseStyles, backgroundColor: '#E1E1E1' }}\r\n aria-label=\"Loading user avatar\"\r\n >\r\n <span style={{ fontSize: `${size * 0.3}px` }}>...</span>\r\n </div>\r\n );\r\n }\r\n\r\n if (photoUrl && !photoError) {\r\n return (\r\n <div\r\n className={className}\r\n style={baseStyles}\r\n title={showTooltip ? displayName : undefined}\r\n aria-label={`${displayName} avatar`}\r\n >\r\n <img\r\n src={photoUrl}\r\n alt={displayName}\r\n style={{ width: '100%', height: '100%', objectFit: 'cover' }}\r\n onError={() => {\r\n setPhotoError(true);\r\n if (fallbackImage) {\r\n setPhotoUrl(fallbackImage);\r\n }\r\n }}\r\n />\r\n </div>\r\n );\r\n }\r\n\r\n return (\r\n <div\r\n className={className}\r\n style={baseStyles}\r\n title={showTooltip ? displayName : undefined}\r\n aria-label={`${displayName} avatar`}\r\n >\r\n {getInitials()}\r\n </div>\r\n );\r\n}\r\n","'use client';\r\n\r\nimport { CSSProperties, ReactNode } from 'react';\r\nimport { useMsalAuth } from '../hooks/useMsalAuth';\r\n\r\nexport interface AuthStatusProps {\r\n /**\r\n * Custom className\r\n */\r\n className?: string;\r\n\r\n /**\r\n * Custom styles\r\n */\r\n style?: CSSProperties;\r\n\r\n /**\r\n * Show detailed status (includes username)\r\n * @default false\r\n */\r\n showDetails?: boolean;\r\n\r\n /**\r\n * Custom render function for loading state\r\n */\r\n renderLoading?: () => ReactNode;\r\n\r\n /**\r\n * Custom render function for authenticated state\r\n */\r\n renderAuthenticated?: (username: string) => ReactNode;\r\n\r\n /**\r\n * Custom render function for unauthenticated state\r\n */\r\n renderUnauthenticated?: () => ReactNode;\r\n}\r\n\r\n/**\r\n * AuthStatus component that shows current authentication state\r\n * \r\n * @example\r\n * ```tsx\r\n * <AuthStatus showDetails />\r\n * ```\r\n */\r\nexport function AuthStatus({\r\n className = '',\r\n style,\r\n showDetails = false,\r\n renderLoading,\r\n renderAuthenticated,\r\n renderUnauthenticated,\r\n}: AuthStatusProps) {\r\n const { isAuthenticated, inProgress, account } = useMsalAuth();\r\n\r\n const baseStyles: CSSProperties = {\r\n display: 'inline-flex',\r\n alignItems: 'center',\r\n gap: '8px',\r\n padding: '8px 12px',\r\n borderRadius: '4px',\r\n fontFamily: '\"Segoe UI\", Tahoma, Geneva, Verdana, sans-serif',\r\n fontSize: '14px',\r\n fontWeight: 500,\r\n ...style,\r\n };\r\n\r\n if (inProgress) {\r\n if (renderLoading) {\r\n return <>{renderLoading()}</>;\r\n }\r\n\r\n return (\r\n <div\r\n className={className}\r\n style={{ ...baseStyles, backgroundColor: '#FFF4CE', color: '#8A6D3B' }}\r\n role=\"status\"\r\n aria-live=\"polite\"\r\n >\r\n <StatusIndicator color=\"#FFA500\" />\r\n <span>Loading...</span>\r\n </div>\r\n );\r\n }\r\n\r\n if (isAuthenticated) {\r\n const username = account?.username || account?.name || 'User';\r\n\r\n if (renderAuthenticated) {\r\n return <>{renderAuthenticated(username)}</>;\r\n }\r\n\r\n return (\r\n <div\r\n className={className}\r\n style={{ ...baseStyles, backgroundColor: '#D4EDDA', color: '#155724' }}\r\n role=\"status\"\r\n aria-live=\"polite\"\r\n >\r\n <StatusIndicator color=\"#28A745\" />\r\n <span>\r\n {showDetails ? `Authenticated as ${username}` : 'Authenticated'}\r\n </span>\r\n </div>\r\n );\r\n }\r\n\r\n if (renderUnauthenticated) {\r\n return <>{renderUnauthenticated()}</>;\r\n }\r\n\r\n return (\r\n <div\r\n className={className}\r\n style={{ ...baseStyles, backgroundColor: '#F8D7DA', color: '#721C24' }}\r\n role=\"status\"\r\n aria-live=\"polite\"\r\n >\r\n <StatusIndicator color=\"#DC3545\" />\r\n <span>Not authenticated</span>\r\n </div>\r\n );\r\n}\r\n\r\nfunction StatusIndicator({ color }: { color: string }) {\r\n return (\r\n <svg width=\"8\" height=\"8\" viewBox=\"0 0 8 8\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\r\n <circle cx=\"4\" cy=\"4\" r=\"4\" fill={color} />\r\n </svg>\r\n );\r\n}\r\n","'use client';\r\n\r\nimport { ReactNode, useEffect } from 'react';\r\nimport { useMsalAuth } from '../hooks/useMsalAuth';\r\n\r\nexport interface AuthGuardProps {\r\n /**\r\n * Content to render when authenticated\r\n */\r\n children: ReactNode;\r\n\r\n /**\r\n * Component to show while checking authentication\r\n */\r\n loadingComponent?: ReactNode;\r\n\r\n /**\r\n * Component to show when not authenticated (before redirect)\r\n */\r\n fallbackComponent?: ReactNode;\r\n\r\n /**\r\n * Use redirect flow instead of popup\r\n * @default true\r\n */\r\n useRedirect?: boolean;\r\n\r\n /**\r\n * Scopes to request during authentication\r\n */\r\n scopes?: string[];\r\n\r\n /**\r\n * Callback when authentication is required\r\n */\r\n onAuthRequired?: () => void;\r\n}\r\n\r\n/**\r\n * AuthGuard component that protects content and auto-redirects to login\r\n * \r\n * @example\r\n * ```tsx\r\n * <AuthGuard>\r\n * <ProtectedContent />\r\n * </AuthGuard>\r\n * ```\r\n */\r\nexport function AuthGuard({\r\n children,\r\n loadingComponent,\r\n fallbackComponent,\r\n useRedirect = true,\r\n scopes,\r\n onAuthRequired,\r\n}: AuthGuardProps) {\r\n const { isAuthenticated, inProgress, loginRedirect, loginPopup } = useMsalAuth();\r\n\r\n useEffect(() => {\r\n if (!isAuthenticated && !inProgress) {\r\n onAuthRequired?.();\r\n \r\n const login = async () => {\r\n try {\r\n if (useRedirect) {\r\n await loginRedirect(scopes);\r\n } else {\r\n await loginPopup(scopes);\r\n }\r\n } catch (error) {\r\n console.error('[AuthGuard] Authentication failed:', error);\r\n }\r\n };\r\n\r\n login();\r\n }\r\n }, [isAuthenticated, inProgress, useRedirect, scopes, loginRedirect, loginPopup, onAuthRequired]);\r\n\r\n if (inProgress) {\r\n return <>{loadingComponent || <div>Authenticating...</div>}</>;\r\n }\r\n\r\n if (!isAuthenticated) {\r\n return <>{fallbackComponent || <div>Redirecting to login...</div>}</>;\r\n }\r\n\r\n return <>{children}</>;\r\n}\r\n","'use client';\r\n\r\nimport { Component, ReactNode, ErrorInfo } from 'react';\r\n\r\nexport interface ErrorBoundaryProps {\r\n /**\r\n * Content to render when no error\r\n */\r\n children: ReactNode;\r\n\r\n /**\r\n * Custom error fallback component\r\n */\r\n fallback?: (error: Error, reset: () => void) => ReactNode;\r\n\r\n /**\r\n * Callback when error occurs\r\n */\r\n onError?: (error: Error, errorInfo: ErrorInfo) => void;\r\n\r\n /**\r\n * Enable debug logging\r\n * @default false\r\n */\r\n debug?: boolean;\r\n}\r\n\r\ninterface ErrorBoundaryState {\r\n hasError: boolean;\r\n error: Error | null;\r\n}\r\n\r\n/**\r\n * Error boundary for catching authentication errors\r\n * \r\n * @example\r\n * ```tsx\r\n * <ErrorBoundary>\r\n * <MsalAuthProvider clientId=\"...\">\r\n * <App />\r\n * </MsalAuthProvider>\r\n * </ErrorBoundary>\r\n * ```\r\n */\r\nexport class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {\r\n constructor(props: ErrorBoundaryProps) {\r\n super(props);\r\n this.state = {\r\n hasError: false,\r\n error: null,\r\n };\r\n }\r\n\r\n static getDerivedStateFromError(error: Error): ErrorBoundaryState {\r\n return {\r\n hasError: true,\r\n error,\r\n };\r\n }\r\n\r\n componentDidCatch(error: Error, errorInfo: ErrorInfo): void {\r\n const { onError, debug } = this.props;\r\n\r\n if (debug) {\r\n console.error('[ErrorBoundary] Caught error:', error);\r\n console.error('[ErrorBoundary] Error info:', errorInfo);\r\n }\r\n\r\n onError?.(error, errorInfo);\r\n }\r\n\r\n reset = (): void => {\r\n this.setState({\r\n hasError: false,\r\n error: null,\r\n });\r\n };\r\n\r\n render(): ReactNode {\r\n const { hasError, error } = this.state;\r\n const { children, fallback } = this.props;\r\n\r\n if (hasError && error) {\r\n if (fallback) {\r\n return fallback(error, this.reset);\r\n }\r\n\r\n return (\r\n <div\r\n style={{\r\n padding: '20px',\r\n margin: '20px',\r\n border: '1px solid #DC3545',\r\n borderRadius: '4px',\r\n backgroundColor: '#F8D7DA',\r\n color: '#721C24',\r\n fontFamily: '\"Segoe UI\", Tahoma, Geneva, Verdana, sans-serif',\r\n }}\r\n >\r\n <h2 style={{ margin: '0 0 10px 0', fontSize: '18px' }}>Authentication Error</h2>\r\n <p style={{ margin: '0 0 10px 0' }}>{error.message}</p>\r\n <button\r\n onClick={this.reset}\r\n style={{\r\n padding: '8px 16px',\r\n backgroundColor: '#DC3545',\r\n color: '#FFFFFF',\r\n border: 'none',\r\n borderRadius: '4px',\r\n cursor: 'pointer',\r\n fontSize: '14px',\r\n fontWeight: 600,\r\n }}\r\n >\r\n Try Again\r\n </button>\r\n </div>\r\n );\r\n }\r\n\r\n return children;\r\n }\r\n}\r\n","'use client';\r\n\r\nimport { useState, useEffect, useCallback } from 'react';\r\nimport { useMsalAuth } from './useMsalAuth';\r\nimport { useGraphApi } from './useGraphApi';\r\nimport { sanitizeError } from '../utils/validation';\r\n\r\nexport interface UseRolesReturn {\r\n /**\r\n * User's Azure AD roles\r\n */\r\n roles: string[];\r\n\r\n /**\r\n * User's Azure AD groups\r\n */\r\n groups: string[];\r\n\r\n /**\r\n * Whether roles/groups are loading\r\n */\r\n loading: boolean;\r\n\r\n /**\r\n * Error if fetch failed\r\n */\r\n error: Error | null;\r\n\r\n /**\r\n * Check if user has a specific role\r\n */\r\n hasRole: (role: string) => boolean;\r\n\r\n /**\r\n * Check if user is in a specific group\r\n */\r\n hasGroup: (groupId: string) => boolean;\r\n\r\n /**\r\n * Check if user has any of the specified roles\r\n */\r\n hasAnyRole: (roles: string[]) => boolean;\r\n\r\n /**\r\n * Check if user has all of the specified roles\r\n */\r\n hasAllRoles: (roles: string[]) => boolean;\r\n\r\n /**\r\n * Refetch roles and groups\r\n */\r\n refetch: () => Promise<void>;\r\n}\r\n\r\n// Simple in-memory cache with size limit\r\nconst rolesCache = new Map<string, { roles: string[]; groups: string[]; timestamp: number }>();\r\nconst CACHE_DURATION = 5 * 60 * 1000; // 5 minutes\r\nconst MAX_CACHE_SIZE = 100; // Prevent memory leaks\r\n\r\n/**\r\n * Clear cache for a specific user or all users\r\n */\r\nfunction clearRolesCache(accountId?: string): void {\r\n if (accountId) {\r\n rolesCache.delete(accountId);\r\n } else {\r\n rolesCache.clear();\r\n }\r\n}\r\n\r\n/**\r\n * Enforce cache size limit using LRU strategy\r\n */\r\nfunction enforceCacheLimit(): void {\r\n if (rolesCache.size > MAX_CACHE_SIZE) {\r\n // Remove oldest entries\r\n const entries = Array.from(rolesCache.entries());\r\n entries.sort((a, b) => a[1].timestamp - b[1].timestamp);\r\n const toRemove = entries.slice(0, rolesCache.size - MAX_CACHE_SIZE);\r\n toRemove.forEach(([key]) => rolesCache.delete(key));\r\n }\r\n}\r\n\r\n/**\r\n * Hook for fetching user's Azure AD roles and groups\r\n * \r\n * @example\r\n * ```tsx\r\n * const { roles, hasRole } = useRoles();\r\n * if (hasRole('Admin')) {\r\n * // Show admin content\r\n * }\r\n * ```\r\n */\r\nexport function useRoles(): UseRolesReturn {\r\n const { isAuthenticated, account } = useMsalAuth();\r\n const graph = useGraphApi();\r\n const [roles, setRoles] = useState<string[]>([]);\r\n const [groups, setGroups] = useState<string[]>([]);\r\n const [loading, setLoading] = useState(false);\r\n const [error, setError] = useState<Error | null>(null);\r\n\r\n const fetchRolesAndGroups = useCallback(async () => {\r\n if (!isAuthenticated || !account) {\r\n setRoles([]);\r\n setGroups([]);\r\n return;\r\n }\r\n\r\n const cacheKey = account.homeAccountId;\r\n\r\n // Check cache\r\n const cached = rolesCache.get(cacheKey);\r\n if (cached && Date.now() - cached.timestamp < CACHE_DURATION) {\r\n setRoles(cached.roles);\r\n setGroups(cached.groups);\r\n return;\r\n }\r\n\r\n setLoading(true);\r\n setError(null);\r\n\r\n try {\r\n // Extract roles from ID token claims\r\n const idTokenClaims = account.idTokenClaims as any;\r\n const tokenRoles = idTokenClaims?.roles || [];\r\n\r\n // Fetch user's groups from Graph API\r\n const groupsResponse = await graph.get<{ value: Array<{ id: string }> }>('/me/memberOf', {\r\n scopes: ['User.Read', 'Directory.Read.All'],\r\n });\r\n\r\n const userGroups = groupsResponse.value.map((group) => group.id);\r\n\r\n // Cache the data\r\n rolesCache.set(cacheKey, {\r\n roles: tokenRoles,\r\n groups: userGroups,\r\n timestamp: Date.now(),\r\n });\r\n\r\n // Enforce cache size limit\r\n enforceCacheLimit();\r\n\r\n setRoles(tokenRoles);\r\n setGroups(userGroups);\r\n } catch (err) {\r\n const error = err as Error;\r\n const sanitizedMessage = sanitizeError(error);\r\n const sanitizedError = new Error(sanitizedMessage);\r\n setError(sanitizedError);\r\n console.error('[Roles] Failed to fetch roles/groups:', sanitizedMessage);\r\n \r\n // Fallback to token claims only\r\n const idTokenClaims = account.idTokenClaims as any;\r\n const tokenRoles = idTokenClaims?.roles || [];\r\n setRoles(tokenRoles);\r\n } finally {\r\n setLoading(false);\r\n }\r\n }, [isAuthenticated, account, graph]);\r\n\r\n const hasRole = useCallback(\r\n (role: string): boolean => {\r\n return roles.includes(role);\r\n },\r\n [roles]\r\n );\r\n\r\n const hasGroup = useCallback(\r\n (groupId: string): boolean => {\r\n return groups.includes(groupId);\r\n },\r\n [groups]\r\n );\r\n\r\n const hasAnyRole = useCallback(\r\n (checkRoles: string[]): boolean => {\r\n return checkRoles.some((role) => roles.includes(role));\r\n },\r\n [roles]\r\n );\r\n\r\n const hasAllRoles = useCallback(\r\n (checkRoles: string[]): boolean => {\r\n return checkRoles.every((role) => roles.includes(role));\r\n },\r\n [roles]\r\n );\r\n\r\n useEffect(() => {\r\n fetchRolesAndGroups();\r\n\r\n // Cleanup cache on unmount\r\n return () => {\r\n if (account) {\r\n clearRolesCache(account.homeAccountId);\r\n }\r\n };\r\n }, [fetchRolesAndGroups, account]);\r\n\r\n return {\r\n roles,\r\n groups,\r\n loading,\r\n error,\r\n hasRole,\r\n hasGroup,\r\n hasAnyRole,\r\n hasAllRoles,\r\n refetch: fetchRolesAndGroups,\r\n };\r\n}\r\n","'use client';\r\n\r\nimport { ComponentType } from 'react';\r\nimport { AuthGuard, AuthGuardProps } from '../components/AuthGuard';\r\n\r\nexport interface WithAuthOptions extends Omit<AuthGuardProps, 'children'> {\r\n /**\r\n * Display name for the wrapped component (for debugging)\r\n */\r\n displayName?: string;\r\n}\r\n\r\n/**\r\n * Higher-order component for protecting pages/components\r\n * \r\n * @example\r\n * ```tsx\r\n * const ProtectedPage = withAuth(MyPage);\r\n * \r\n * // With options\r\n * const ProtectedPage = withAuth(MyPage, {\r\n * useRedirect: true,\r\n * scopes: ['User.Read', 'Mail.Read']\r\n * });\r\n * ```\r\n */\r\nexport function withAuth<P extends object>(\r\n Component: ComponentType<P>,\r\n options: WithAuthOptions = {}\r\n): ComponentType<P> {\r\n const { displayName, ...guardProps } = options;\r\n\r\n const WrappedComponent = (props: P) => {\r\n return (\r\n <AuthGuard {...guardProps}>\r\n <Component {...props} />\r\n </AuthGuard>\r\n );\r\n };\r\n\r\n WrappedComponent.displayName = displayName || `withAuth(${Component.displayName || Component.name || 'Component'})`;\r\n\r\n return WrappedComponent;\r\n}\r\n","/**\r\n * Retry configuration for token acquisition\r\n */\r\nexport interface RetryConfig {\r\n /**\r\n * Maximum number of retry attempts\r\n * @default 3\r\n */\r\n maxRetries?: number;\r\n\r\n /**\r\n * Initial delay in milliseconds\r\n * @default 1000\r\n */\r\n initialDelay?: number;\r\n\r\n /**\r\n * Maximum delay in milliseconds\r\n * @default 10000\r\n */\r\n maxDelay?: number;\r\n\r\n /**\r\n * Backoff multiplier\r\n * @default 2\r\n */\r\n backoffMultiplier?: number;\r\n\r\n /**\r\n * Enable debug logging\r\n * @default false\r\n */\r\n debug?: boolean;\r\n}\r\n\r\n/**\r\n * Exponential backoff retry utility for token acquisition\r\n * \r\n * @example\r\n * ```tsx\r\n * const token = await retryWithBackoff(\r\n * () => acquireTokenSilent(scopes),\r\n * { maxRetries: 3, debug: true }\r\n * );\r\n * ```\r\n */\r\nexport async function retryWithBackoff<T>(\r\n fn: () => Promise<T>,\r\n config: RetryConfig = {}\r\n): Promise<T> {\r\n const {\r\n maxRetries = 3,\r\n initialDelay = 1000,\r\n maxDelay = 10000,\r\n backoffMultiplier = 2,\r\n debug = false,\r\n } = config;\r\n\r\n let lastError: Error | undefined;\r\n let delay = initialDelay;\r\n\r\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\r\n try {\r\n if (debug && attempt > 0) {\r\n console.log(`[TokenRetry] Attempt ${attempt + 1}/${maxRetries + 1}`);\r\n }\r\n\r\n return await fn();\r\n } catch (error) {\r\n lastError = error as Error;\r\n\r\n if (attempt === maxRetries) {\r\n if (debug) {\r\n console.error('[TokenRetry] All retry attempts failed');\r\n }\r\n break;\r\n }\r\n\r\n // Check if error is retryable\r\n if (!isRetryableError(error as Error)) {\r\n if (debug) {\r\n console.log('[TokenRetry] Non-retryable error, aborting');\r\n }\r\n throw error;\r\n }\r\n\r\n if (debug) {\r\n console.warn(`[TokenRetry] Attempt ${attempt + 1} failed, retrying in ${delay}ms...`);\r\n }\r\n\r\n // Wait before retrying\r\n await sleep(delay);\r\n\r\n // Exponential backoff\r\n delay = Math.min(delay * backoffMultiplier, maxDelay);\r\n }\r\n }\r\n\r\n throw lastError;\r\n}\r\n\r\n/**\r\n * Check if an error is retryable\r\n */\r\nfunction isRetryableError(error: Error): boolean {\r\n const message = error.message.toLowerCase();\r\n\r\n // Network errors are retryable\r\n if (\r\n message.includes('network') ||\r\n message.includes('timeout') ||\r\n message.includes('fetch') ||\r\n message.includes('connection')\r\n ) {\r\n return true;\r\n }\r\n\r\n // Server errors (5xx) are retryable\r\n if (message.includes('500') || message.includes('502') || message.includes('503')) {\r\n return true;\r\n }\r\n\r\n // Rate limiting is retryable\r\n if (message.includes('429') || message.includes('rate limit')) {\r\n return true;\r\n }\r\n\r\n // Token refresh errors are retryable\r\n if (message.includes('token') && message.includes('expired')) {\r\n return true;\r\n }\r\n\r\n return false;\r\n}\r\n\r\n/**\r\n * Sleep utility\r\n */\r\nfunction sleep(ms: number): Promise<void> {\r\n return new Promise((resolve) => setTimeout(resolve, ms));\r\n}\r\n\r\n/**\r\n * Create a retry wrapper for a function\r\n * \r\n * @example\r\n * ```tsx\r\n * const acquireTokenWithRetry = createRetryWrapper(acquireToken, {\r\n * maxRetries: 3,\r\n * debug: true\r\n * });\r\n * \r\n * const token = await acquireTokenWithRetry(scopes);\r\n * ```\r\n */\r\nexport function createRetryWrapper<TArgs extends any[], TReturn>(\r\n fn: (...args: TArgs) => Promise<TReturn>,\r\n config: RetryConfig = {}\r\n): (...args: TArgs) => Promise<TReturn> {\r\n return (...args: TArgs) => {\r\n return retryWithBackoff(() => fn(...args), config);\r\n };\r\n}\r\n","/**\r\n * Debug logger configuration\r\n */\r\nexport interface DebugLoggerConfig {\r\n /**\r\n * Enable debug mode\r\n * @default false\r\n */\r\n enabled?: boolean;\r\n\r\n /**\r\n * Prefix for log messages\r\n * @default '[MSAL-Next]'\r\n */\r\n prefix?: string;\r\n\r\n /**\r\n * Show timestamps\r\n * @default true\r\n */\r\n showTimestamp?: boolean;\r\n\r\n /**\r\n * Log level\r\n * @default 'info'\r\n */\r\n level?: 'error' | 'warn' | 'info' | 'debug';\r\n}\r\n\r\nclass DebugLogger {\r\n private config: Required<DebugLoggerConfig>;\r\n\r\n constructor(config: DebugLoggerConfig = {}) {\r\n this.config = {\r\n enabled: config.enabled ?? false,\r\n prefix: config.prefix ?? '[MSAL-Next]',\r\n showTimestamp: config.showTimestamp ?? true,\r\n level: config.level ?? 'info',\r\n };\r\n }\r\n\r\n private shouldLog(level: string): boolean {\r\n if (!this.config.enabled) return false;\r\n\r\n const levels = ['error', 'warn', 'info', 'debug'];\r\n const currentLevelIndex = levels.indexOf(this.config.level);\r\n const messageLevelIndex = levels.indexOf(level);\r\n\r\n return messageLevelIndex <= currentLevelIndex;\r\n }\r\n\r\n private formatMessage(level: string, message: string, data?: any): string {\r\n const timestamp = this.config.showTimestamp ? `[${new Date().toISOString()}]` : '';\r\n const prefix = this.config.prefix;\r\n const levelStr = `[${level.toUpperCase()}]`;\r\n\r\n let formatted = `${timestamp} ${prefix} ${levelStr} ${message}`;\r\n\r\n if (data !== undefined) {\r\n formatted += '\\n' + JSON.stringify(data, null, 2);\r\n }\r\n\r\n return formatted;\r\n }\r\n\r\n error(message: string, data?: any): void {\r\n if (this.shouldLog('error')) {\r\n console.error(this.formatMessage('error', message, data));\r\n }\r\n }\r\n\r\n warn(message: string, data?: any): void {\r\n if (this.shouldLog('warn')) {\r\n console.warn(this.formatMessage('warn', message, data));\r\n }\r\n }\r\n\r\n info(message: string, data?: any): void {\r\n if (this.shouldLog('info')) {\r\n console.info(this.formatMessage('info', message, data));\r\n }\r\n }\r\n\r\n debug(message: string, data?: any): void {\r\n if (this.shouldLog('debug')) {\r\n console.debug(this.formatMessage('debug', message, data));\r\n }\r\n }\r\n\r\n group(label: string): void {\r\n if (this.config.enabled) {\r\n console.group(`${this.config.prefix} ${label}`);\r\n }\r\n }\r\n\r\n groupEnd(): void {\r\n if (this.config.enabled) {\r\n console.groupEnd();\r\n }\r\n }\r\n\r\n setEnabled(enabled: boolean): void {\r\n this.config.enabled = enabled;\r\n }\r\n\r\n setLevel(level: DebugLoggerConfig['level']): void {\r\n if (level) {\r\n this.config.level = level;\r\n }\r\n }\r\n}\r\n\r\n// Global logger instance\r\nlet globalLogger: DebugLogger | null = null;\r\n\r\n/**\r\n * Get or create the global debug logger\r\n * \r\n * @example\r\n * ```tsx\r\n * const logger = getDebugLogger({ enabled: true, level: 'debug' });\r\n * logger.info('User logged in', { username: 'user@example.com' });\r\n * ```\r\n */\r\nexport function getDebugLogger(config?: DebugLoggerConfig): DebugLogger {\r\n if (!globalLogger) {\r\n globalLogger = new DebugLogger(config);\r\n } else if (config) {\r\n // Update config if provided\r\n if (config.enabled !== undefined) {\r\n globalLogger.setEnabled(config.enabled);\r\n }\r\n if (config.level) {\r\n globalLogger.setLevel(config.level);\r\n }\r\n }\r\n\r\n return globalLogger;\r\n}\r\n\r\n/**\r\n * Create a scoped logger with a custom prefix\r\n * \r\n * @example\r\n * ```tsx\r\n * const logger = createScopedLogger('GraphAPI', { enabled: true });\r\n * logger.info('Fetching user profile');\r\n * ```\r\n */\r\nexport function createScopedLogger(scope: string, config?: DebugLoggerConfig): DebugLogger {\r\n return new DebugLogger({\r\n ...config,\r\n prefix: `[MSAL-Next:${scope}]`,\r\n });\r\n}\r\n","import { NextRequest, NextResponse } from 'next/server';\r\nimport { safeJsonParse, isValidAccountData } from '../utils/validation';\r\n\r\nexport interface AuthMiddlewareConfig {\r\n /**\r\n * Routes that require authentication\r\n * @example ['/dashboard', '/profile', '/api/protected']\r\n */\r\n protectedRoutes?: string[];\r\n\r\n /**\r\n * Routes that should be accessible only when NOT authenticated\r\n * @example ['/login', '/signup']\r\n */\r\n publicOnlyRoutes?: string[];\r\n\r\n /**\r\n * Login page path\r\n * @default '/login'\r\n */\r\n loginPath?: string;\r\n\r\n /**\r\n * Redirect path after login\r\n * @default '/'\r\n */\r\n redirectAfterLogin?: string;\r\n\r\n /**\r\n * Cookie name for session\r\n * @default 'msal.account'\r\n */\r\n sessionCookie?: string;\r\n\r\n /**\r\n * Custom authentication check function\r\n */\r\n isAuthenticated?: (request: NextRequest) => boolean | Promise<boolean>;\r\n\r\n /**\r\n * Enable debug logging\r\n * @default false\r\n */\r\n debug?: boolean;\r\n}\r\n\r\n/**\r\n * Creates authentication middleware for Next.js App Router\r\n * \r\n * @example\r\n * ```tsx\r\n * // middleware.ts\r\n * import { createAuthMiddleware } from '@chemmangat/msal-next';\r\n * \r\n * export const middleware = createAuthMiddleware({\r\n * protectedRoutes: ['/dashboard', '/profile'],\r\n * publicOnlyRoutes: ['/login'],\r\n * loginPath: '/login',\r\n * });\r\n * \r\n * export const config = {\r\n * matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'],\r\n * };\r\n * ```\r\n */\r\nexport function createAuthMiddleware(config: AuthMiddlewareConfig = {}) {\r\n const {\r\n protectedRoutes = [],\r\n publicOnlyRoutes = [],\r\n loginPath = '/login',\r\n redirectAfterLogin = '/',\r\n sessionCookie = 'msal.account',\r\n isAuthenticated: customAuthCheck,\r\n debug = false,\r\n } = config;\r\n\r\n return async function authMiddleware(request: NextRequest) {\r\n const { pathname } = request.nextUrl;\r\n\r\n if (debug) {\r\n console.log('[AuthMiddleware] Processing:', pathname);\r\n }\r\n\r\n // Check if user is authenticated\r\n let authenticated = false;\r\n\r\n if (customAuthCheck) {\r\n authenticated = await customAuthCheck(request);\r\n } else {\r\n // Default: check for session cookie\r\n const sessionData = request.cookies.get(sessionCookie);\r\n authenticated = !!sessionData?.value;\r\n }\r\n\r\n if (debug) {\r\n console.log('[AuthMiddleware] Authenticated:', authenticated);\r\n }\r\n\r\n // Check if route is protected\r\n const isProtectedRoute = protectedRoutes.some((route) =>\r\n pathname.startsWith(route)\r\n );\r\n\r\n // Check if route is public-only\r\n const isPublicOnlyRoute = publicOnlyRoutes.some((route) =>\r\n pathname.startsWith(route)\r\n );\r\n\r\n // Redirect unauthenticated users from protected routes\r\n if (isProtectedRoute && !authenticated) {\r\n if (debug) {\r\n console.log('[AuthMiddleware] Redirecting to login');\r\n }\r\n\r\n const url = request.nextUrl.clone();\r\n url.pathname = loginPath;\r\n url.searchParams.set('returnUrl', pathname);\r\n return NextResponse.redirect(url);\r\n }\r\n\r\n // Redirect authenticated users from public-only routes\r\n if (isPublicOnlyRoute && authenticated) {\r\n if (debug) {\r\n console.log('[AuthMiddleware] Redirecting to home');\r\n }\r\n\r\n const returnUrl = request.nextUrl.searchParams.get('returnUrl');\r\n const url = request.nextUrl.clone();\r\n url.pathname = returnUrl || redirectAfterLogin;\r\n url.searchParams.delete('returnUrl');\r\n return NextResponse.redirect(url);\r\n }\r\n\r\n // Add auth headers for server components\r\n const response = NextResponse.next();\r\n if (authenticated) {\r\n response.headers.set('x-msal-authenticated', 'true');\r\n \r\n // Try to add username from cookie with validation\r\n try {\r\n const sessionData = request.cookies.get(sessionCookie);\r\n if (sessionData?.value) {\r\n const account = safeJsonParse(sessionData.value, isValidAccountData);\r\n if (account?.username) {\r\n response.headers.set('x-msal-username', account.username);\r\n }\r\n }\r\n } catch (error) {\r\n // Ignore parsing errors\r\n if (debug) {\r\n console.warn('[AuthMiddleware] Failed to parse session data');\r\n }\r\n }\r\n }\r\n\r\n return response;\r\n };\r\n}\r\n"]}
|