@chemmangat/msal-next 1.2.1 → 2.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/README.md +440 -179
- package/dist/index.d.mts +589 -2
- package/dist/index.d.ts +589 -2
- package/dist/index.js +2 -425
- package/dist/index.mjs +2 -393
- package/dist/server.d.mts +53 -0
- package/dist/server.d.ts +53 -0
- package/dist/server.js +1 -0
- package/dist/server.mjs +1 -0
- package/package.json +19 -4
- package/dist/index.js.map +0 -1
- package/dist/index.mjs.map +0 -1
package/dist/index.mjs
CHANGED
|
@@ -1,393 +1,2 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
|
|
3
|
-
// src/components/MsalAuthProvider.tsx
|
|
4
|
-
import { MsalProvider } from "@azure/msal-react";
|
|
5
|
-
import { PublicClientApplication, EventType } from "@azure/msal-browser";
|
|
6
|
-
import { useEffect, useState, useRef } from "react";
|
|
7
|
-
|
|
8
|
-
// src/utils/createMsalConfig.ts
|
|
9
|
-
import { LogLevel } from "@azure/msal-browser";
|
|
10
|
-
function createMsalConfig(config) {
|
|
11
|
-
if (config.msalConfig) {
|
|
12
|
-
return config.msalConfig;
|
|
13
|
-
}
|
|
14
|
-
const {
|
|
15
|
-
clientId,
|
|
16
|
-
tenantId,
|
|
17
|
-
authorityType = "common",
|
|
18
|
-
redirectUri,
|
|
19
|
-
postLogoutRedirectUri,
|
|
20
|
-
cacheLocation = "sessionStorage",
|
|
21
|
-
storeAuthStateInCookie = false,
|
|
22
|
-
navigateToLoginRequestUrl = true,
|
|
23
|
-
enableLogging = false,
|
|
24
|
-
loggerCallback
|
|
25
|
-
} = config;
|
|
26
|
-
if (!clientId) {
|
|
27
|
-
throw new Error("@chemmangat/msal-next: clientId is required");
|
|
28
|
-
}
|
|
29
|
-
const getAuthority = () => {
|
|
30
|
-
if (authorityType === "tenant") {
|
|
31
|
-
if (!tenantId) {
|
|
32
|
-
throw new Error('@chemmangat/msal-next: tenantId is required when authorityType is "tenant"');
|
|
33
|
-
}
|
|
34
|
-
return `https://login.microsoftonline.com/${tenantId}`;
|
|
35
|
-
}
|
|
36
|
-
return `https://login.microsoftonline.com/${authorityType}`;
|
|
37
|
-
};
|
|
38
|
-
const defaultRedirectUri = typeof window !== "undefined" ? window.location.origin : "http://localhost:3000";
|
|
39
|
-
const finalRedirectUri = redirectUri || defaultRedirectUri;
|
|
40
|
-
const msalConfig = {
|
|
41
|
-
auth: {
|
|
42
|
-
clientId,
|
|
43
|
-
authority: getAuthority(),
|
|
44
|
-
redirectUri: finalRedirectUri,
|
|
45
|
-
postLogoutRedirectUri: postLogoutRedirectUri || finalRedirectUri,
|
|
46
|
-
navigateToLoginRequestUrl
|
|
47
|
-
},
|
|
48
|
-
cache: {
|
|
49
|
-
cacheLocation,
|
|
50
|
-
storeAuthStateInCookie
|
|
51
|
-
},
|
|
52
|
-
system: {
|
|
53
|
-
loggerOptions: {
|
|
54
|
-
loggerCallback: loggerCallback || ((level, message, containsPii) => {
|
|
55
|
-
if (containsPii || !enableLogging) return;
|
|
56
|
-
switch (level) {
|
|
57
|
-
case LogLevel.Error:
|
|
58
|
-
console.error("[MSAL]", message);
|
|
59
|
-
break;
|
|
60
|
-
case LogLevel.Warning:
|
|
61
|
-
console.warn("[MSAL]", message);
|
|
62
|
-
break;
|
|
63
|
-
case LogLevel.Info:
|
|
64
|
-
console.info("[MSAL]", message);
|
|
65
|
-
break;
|
|
66
|
-
case LogLevel.Verbose:
|
|
67
|
-
console.debug("[MSAL]", message);
|
|
68
|
-
break;
|
|
69
|
-
}
|
|
70
|
-
}),
|
|
71
|
-
logLevel: enableLogging ? LogLevel.Verbose : LogLevel.Error
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
};
|
|
75
|
-
return msalConfig;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
// src/components/MsalAuthProvider.tsx
|
|
79
|
-
import { Fragment, jsx } from "react/jsx-runtime";
|
|
80
|
-
var globalMsalInstance = null;
|
|
81
|
-
function getMsalInstance() {
|
|
82
|
-
return globalMsalInstance;
|
|
83
|
-
}
|
|
84
|
-
function MsalAuthProvider({ children, loadingComponent, onInitialized, ...config }) {
|
|
85
|
-
const [msalInstance, setMsalInstance] = useState(null);
|
|
86
|
-
const instanceRef = useRef(null);
|
|
87
|
-
useEffect(() => {
|
|
88
|
-
if (typeof window === "undefined") {
|
|
89
|
-
return;
|
|
90
|
-
}
|
|
91
|
-
if (instanceRef.current) {
|
|
92
|
-
return;
|
|
93
|
-
}
|
|
94
|
-
const initializeMsal = async () => {
|
|
95
|
-
try {
|
|
96
|
-
const msalConfig = createMsalConfig(config);
|
|
97
|
-
const instance = new PublicClientApplication(msalConfig);
|
|
98
|
-
await instance.initialize();
|
|
99
|
-
const response = await instance.handleRedirectPromise();
|
|
100
|
-
if (response && config.enableLogging) {
|
|
101
|
-
console.log("[MSAL] Redirect authentication successful");
|
|
102
|
-
}
|
|
103
|
-
const enableLogging = config.enableLogging || false;
|
|
104
|
-
instance.addEventCallback((event) => {
|
|
105
|
-
if (event.eventType === EventType.LOGIN_SUCCESS) {
|
|
106
|
-
if (enableLogging) {
|
|
107
|
-
const payload = event.payload;
|
|
108
|
-
console.log("[MSAL] Login successful:", payload.account?.username);
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
if (event.eventType === EventType.LOGIN_FAILURE) {
|
|
112
|
-
console.error("[MSAL] Login failed:", event.error);
|
|
113
|
-
}
|
|
114
|
-
if (event.eventType === EventType.LOGOUT_SUCCESS) {
|
|
115
|
-
if (enableLogging) {
|
|
116
|
-
console.log("[MSAL] Logout successful");
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
});
|
|
120
|
-
instanceRef.current = instance;
|
|
121
|
-
globalMsalInstance = instance;
|
|
122
|
-
setMsalInstance(instance);
|
|
123
|
-
if (onInitialized) {
|
|
124
|
-
onInitialized(instance);
|
|
125
|
-
}
|
|
126
|
-
} catch (error) {
|
|
127
|
-
console.error("[MSAL] Initialization failed:", error);
|
|
128
|
-
throw error;
|
|
129
|
-
}
|
|
130
|
-
};
|
|
131
|
-
initializeMsal();
|
|
132
|
-
}, []);
|
|
133
|
-
if (typeof window === "undefined") {
|
|
134
|
-
return /* @__PURE__ */ jsx(Fragment, { children: loadingComponent || /* @__PURE__ */ jsx("div", { children: "Loading authentication..." }) });
|
|
135
|
-
}
|
|
136
|
-
if (!msalInstance) {
|
|
137
|
-
return /* @__PURE__ */ jsx(Fragment, { children: loadingComponent || /* @__PURE__ */ jsx("div", { children: "Loading authentication..." }) });
|
|
138
|
-
}
|
|
139
|
-
return /* @__PURE__ */ jsx(MsalProvider, { instance: msalInstance, children });
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
// src/hooks/useMsalAuth.ts
|
|
143
|
-
import { useMsal, useAccount } from "@azure/msal-react";
|
|
144
|
-
import { InteractionStatus } from "@azure/msal-browser";
|
|
145
|
-
import { useCallback, useMemo } from "react";
|
|
146
|
-
function useMsalAuth(defaultScopes = ["User.Read"]) {
|
|
147
|
-
const { instance, accounts, inProgress } = useMsal();
|
|
148
|
-
const account = useAccount(accounts[0] || null);
|
|
149
|
-
const isAuthenticated = useMemo(() => accounts.length > 0, [accounts]);
|
|
150
|
-
const loginPopup = useCallback(
|
|
151
|
-
async (scopes = defaultScopes) => {
|
|
152
|
-
try {
|
|
153
|
-
const request = {
|
|
154
|
-
scopes,
|
|
155
|
-
prompt: "select_account"
|
|
156
|
-
};
|
|
157
|
-
await instance.loginPopup(request);
|
|
158
|
-
} catch (error) {
|
|
159
|
-
console.error("[MSAL] Login popup failed:", error);
|
|
160
|
-
throw error;
|
|
161
|
-
}
|
|
162
|
-
},
|
|
163
|
-
[instance, defaultScopes]
|
|
164
|
-
);
|
|
165
|
-
const loginRedirect = useCallback(
|
|
166
|
-
async (scopes = defaultScopes) => {
|
|
167
|
-
try {
|
|
168
|
-
const request = {
|
|
169
|
-
scopes,
|
|
170
|
-
prompt: "select_account"
|
|
171
|
-
};
|
|
172
|
-
await instance.loginRedirect(request);
|
|
173
|
-
} catch (error) {
|
|
174
|
-
console.error("[MSAL] Login redirect failed:", error);
|
|
175
|
-
throw error;
|
|
176
|
-
}
|
|
177
|
-
},
|
|
178
|
-
[instance, defaultScopes]
|
|
179
|
-
);
|
|
180
|
-
const logoutPopup = useCallback(async () => {
|
|
181
|
-
try {
|
|
182
|
-
await instance.logoutPopup({
|
|
183
|
-
account: account || void 0
|
|
184
|
-
});
|
|
185
|
-
} catch (error) {
|
|
186
|
-
console.error("[MSAL] Logout popup failed:", error);
|
|
187
|
-
throw error;
|
|
188
|
-
}
|
|
189
|
-
}, [instance, account]);
|
|
190
|
-
const logoutRedirect = useCallback(async () => {
|
|
191
|
-
try {
|
|
192
|
-
await instance.logoutRedirect({
|
|
193
|
-
account: account || void 0
|
|
194
|
-
});
|
|
195
|
-
} catch (error) {
|
|
196
|
-
console.error("[MSAL] Logout redirect failed:", error);
|
|
197
|
-
throw error;
|
|
198
|
-
}
|
|
199
|
-
}, [instance, account]);
|
|
200
|
-
const acquireTokenSilent = useCallback(
|
|
201
|
-
async (scopes = defaultScopes) => {
|
|
202
|
-
if (!account) {
|
|
203
|
-
throw new Error("[MSAL] No active account. Please login first.");
|
|
204
|
-
}
|
|
205
|
-
try {
|
|
206
|
-
const request = {
|
|
207
|
-
scopes,
|
|
208
|
-
account
|
|
209
|
-
};
|
|
210
|
-
const response = await instance.acquireTokenSilent(request);
|
|
211
|
-
return response.accessToken;
|
|
212
|
-
} catch (error) {
|
|
213
|
-
console.error("[MSAL] Silent token acquisition failed:", error);
|
|
214
|
-
throw error;
|
|
215
|
-
}
|
|
216
|
-
},
|
|
217
|
-
[instance, account, defaultScopes]
|
|
218
|
-
);
|
|
219
|
-
const acquireTokenPopup = useCallback(
|
|
220
|
-
async (scopes = defaultScopes) => {
|
|
221
|
-
if (!account) {
|
|
222
|
-
throw new Error("[MSAL] No active account. Please login first.");
|
|
223
|
-
}
|
|
224
|
-
try {
|
|
225
|
-
const request = {
|
|
226
|
-
scopes,
|
|
227
|
-
account
|
|
228
|
-
};
|
|
229
|
-
const response = await instance.acquireTokenPopup(request);
|
|
230
|
-
return response.accessToken;
|
|
231
|
-
} catch (error) {
|
|
232
|
-
console.error("[MSAL] Token popup acquisition failed:", error);
|
|
233
|
-
throw error;
|
|
234
|
-
}
|
|
235
|
-
},
|
|
236
|
-
[instance, account, defaultScopes]
|
|
237
|
-
);
|
|
238
|
-
const acquireTokenRedirect = useCallback(
|
|
239
|
-
async (scopes = defaultScopes) => {
|
|
240
|
-
if (!account) {
|
|
241
|
-
throw new Error("[MSAL] No active account. Please login first.");
|
|
242
|
-
}
|
|
243
|
-
try {
|
|
244
|
-
const request = {
|
|
245
|
-
scopes,
|
|
246
|
-
account
|
|
247
|
-
};
|
|
248
|
-
await instance.acquireTokenRedirect(request);
|
|
249
|
-
} catch (error) {
|
|
250
|
-
console.error("[MSAL] Token redirect acquisition failed:", error);
|
|
251
|
-
throw error;
|
|
252
|
-
}
|
|
253
|
-
},
|
|
254
|
-
[instance, account, defaultScopes]
|
|
255
|
-
);
|
|
256
|
-
const acquireToken = useCallback(
|
|
257
|
-
async (scopes = defaultScopes) => {
|
|
258
|
-
try {
|
|
259
|
-
return await acquireTokenSilent(scopes);
|
|
260
|
-
} catch (error) {
|
|
261
|
-
console.warn("[MSAL] Silent token acquisition failed, falling back to popup");
|
|
262
|
-
return await acquireTokenPopup(scopes);
|
|
263
|
-
}
|
|
264
|
-
},
|
|
265
|
-
[acquireTokenSilent, acquireTokenPopup, defaultScopes]
|
|
266
|
-
);
|
|
267
|
-
const clearSession = useCallback(async () => {
|
|
268
|
-
instance.setActiveAccount(null);
|
|
269
|
-
await instance.clearCache();
|
|
270
|
-
}, [instance]);
|
|
271
|
-
return {
|
|
272
|
-
account,
|
|
273
|
-
accounts,
|
|
274
|
-
isAuthenticated,
|
|
275
|
-
inProgress: inProgress !== InteractionStatus.None,
|
|
276
|
-
loginPopup,
|
|
277
|
-
loginRedirect,
|
|
278
|
-
logoutPopup,
|
|
279
|
-
logoutRedirect,
|
|
280
|
-
acquireToken,
|
|
281
|
-
acquireTokenSilent,
|
|
282
|
-
acquireTokenPopup,
|
|
283
|
-
acquireTokenRedirect,
|
|
284
|
-
clearSession
|
|
285
|
-
};
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
// src/components/MicrosoftSignInButton.tsx
|
|
289
|
-
import { jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
290
|
-
function MicrosoftSignInButton({
|
|
291
|
-
text = "Sign in with Microsoft",
|
|
292
|
-
variant = "dark",
|
|
293
|
-
size = "medium",
|
|
294
|
-
useRedirect = false,
|
|
295
|
-
scopes,
|
|
296
|
-
className = "",
|
|
297
|
-
style,
|
|
298
|
-
onSuccess,
|
|
299
|
-
onError
|
|
300
|
-
}) {
|
|
301
|
-
const { loginPopup, loginRedirect, inProgress } = useMsalAuth();
|
|
302
|
-
const handleClick = async () => {
|
|
303
|
-
try {
|
|
304
|
-
if (useRedirect) {
|
|
305
|
-
await loginRedirect(scopes);
|
|
306
|
-
} else {
|
|
307
|
-
await loginPopup(scopes);
|
|
308
|
-
}
|
|
309
|
-
onSuccess?.();
|
|
310
|
-
} catch (error) {
|
|
311
|
-
onError?.(error);
|
|
312
|
-
}
|
|
313
|
-
};
|
|
314
|
-
const sizeStyles = {
|
|
315
|
-
small: {
|
|
316
|
-
padding: "8px 16px",
|
|
317
|
-
fontSize: "14px",
|
|
318
|
-
height: "36px"
|
|
319
|
-
},
|
|
320
|
-
medium: {
|
|
321
|
-
padding: "10px 20px",
|
|
322
|
-
fontSize: "15px",
|
|
323
|
-
height: "41px"
|
|
324
|
-
},
|
|
325
|
-
large: {
|
|
326
|
-
padding: "12px 24px",
|
|
327
|
-
fontSize: "16px",
|
|
328
|
-
height: "48px"
|
|
329
|
-
}
|
|
330
|
-
};
|
|
331
|
-
const variantStyles = {
|
|
332
|
-
dark: {
|
|
333
|
-
backgroundColor: "#2F2F2F",
|
|
334
|
-
color: "#FFFFFF",
|
|
335
|
-
border: "1px solid #8C8C8C"
|
|
336
|
-
},
|
|
337
|
-
light: {
|
|
338
|
-
backgroundColor: "#FFFFFF",
|
|
339
|
-
color: "#5E5E5E",
|
|
340
|
-
border: "1px solid #8C8C8C"
|
|
341
|
-
}
|
|
342
|
-
};
|
|
343
|
-
const baseStyles = {
|
|
344
|
-
display: "inline-flex",
|
|
345
|
-
alignItems: "center",
|
|
346
|
-
justifyContent: "center",
|
|
347
|
-
gap: "12px",
|
|
348
|
-
fontFamily: '"Segoe UI", Tahoma, Geneva, Verdana, sans-serif',
|
|
349
|
-
fontWeight: 600,
|
|
350
|
-
borderRadius: "2px",
|
|
351
|
-
cursor: inProgress ? "not-allowed" : "pointer",
|
|
352
|
-
transition: "all 0.2s ease",
|
|
353
|
-
opacity: inProgress ? 0.6 : 1,
|
|
354
|
-
...variantStyles[variant],
|
|
355
|
-
...sizeStyles[size],
|
|
356
|
-
...style
|
|
357
|
-
};
|
|
358
|
-
return /* @__PURE__ */ jsxs(
|
|
359
|
-
"button",
|
|
360
|
-
{
|
|
361
|
-
onClick: handleClick,
|
|
362
|
-
disabled: inProgress,
|
|
363
|
-
className,
|
|
364
|
-
style: baseStyles,
|
|
365
|
-
"aria-label": text,
|
|
366
|
-
children: [
|
|
367
|
-
/* @__PURE__ */ jsx2(MicrosoftLogo, {}),
|
|
368
|
-
/* @__PURE__ */ jsx2("span", { children: text })
|
|
369
|
-
]
|
|
370
|
-
}
|
|
371
|
-
);
|
|
372
|
-
}
|
|
373
|
-
function MicrosoftLogo() {
|
|
374
|
-
return /* @__PURE__ */ jsxs("svg", { width: "21", height: "21", viewBox: "0 0 21 21", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [
|
|
375
|
-
/* @__PURE__ */ jsx2("rect", { width: "10", height: "10", fill: "#F25022" }),
|
|
376
|
-
/* @__PURE__ */ jsx2("rect", { x: "11", width: "10", height: "10", fill: "#7FBA00" }),
|
|
377
|
-
/* @__PURE__ */ jsx2("rect", { y: "11", width: "10", height: "10", fill: "#00A4EF" }),
|
|
378
|
-
/* @__PURE__ */ jsx2("rect", { x: "11", y: "11", width: "10", height: "10", fill: "#FFB900" })
|
|
379
|
-
] });
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
// src/index.ts
|
|
383
|
-
import { useMsal as useMsal2, useIsAuthenticated, useAccount as useAccount2 } from "@azure/msal-react";
|
|
384
|
-
export {
|
|
385
|
-
MicrosoftSignInButton,
|
|
386
|
-
MsalAuthProvider,
|
|
387
|
-
getMsalInstance,
|
|
388
|
-
useAccount2 as useAccount,
|
|
389
|
-
useIsAuthenticated,
|
|
390
|
-
useMsal2 as useMsal,
|
|
391
|
-
useMsalAuth
|
|
392
|
-
};
|
|
393
|
-
//# sourceMappingURL=index.mjs.map
|
|
1
|
+
import {MsalProvider,useMsal,useAccount}from'@azure/msal-react';export{useAccount,useIsAuthenticated,useMsal}from'@azure/msal-react';import {LogLevel,PublicClientApplication,EventType,InteractionStatus}from'@azure/msal-browser';import {useState,useRef,useEffect,useMemo,useCallback,Component}from'react';import {jsx,Fragment,jsxs}from'react/jsx-runtime';import {NextResponse}from'next/server';function G(r){if(r.msalConfig)return r.msalConfig;let{clientId:e,tenantId:o,authorityType:s="common",redirectUri:n,postLogoutRedirectUri:u,cacheLocation:p="sessionStorage",storeAuthStateInCookie:l=false,navigateToLoginRequestUrl:c=true,enableLogging:i=false,loggerCallback:f}=r;if(!e)throw new Error("@chemmangat/msal-next: clientId is required");let g=()=>{if(s==="tenant"){if(!o)throw new Error('@chemmangat/msal-next: tenantId is required when authorityType is "tenant"');return `https://login.microsoftonline.com/${o}`}return `https://login.microsoftonline.com/${s}`},h=typeof window<"u"?window.location.origin:"http://localhost:3000",d=n||h;return {auth:{clientId:e,authority:g(),redirectUri:d,postLogoutRedirectUri:u||d,navigateToLoginRequestUrl:c},cache:{cacheLocation:p,storeAuthStateInCookie:l},system:{loggerOptions:{loggerCallback:f||((a,t,y)=>{if(!(y||!i))switch(a){case LogLevel.Error:console.error("[MSAL]",t);break;case LogLevel.Warning:console.warn("[MSAL]",t);break;case LogLevel.Info:console.info("[MSAL]",t);break;case LogLevel.Verbose:console.debug("[MSAL]",t);break}}),logLevel:i?LogLevel.Verbose:LogLevel.Error}}}}var Q=null;function pe(){return Q}function de({children:r,loadingComponent:e,onInitialized:o,...s}){let[n,u]=useState(null),p=useRef(null);return useEffect(()=>{if(typeof window>"u"||p.current)return;(async()=>{try{let c=G(s),i=new PublicClientApplication(c);await i.initialize(),await i.handleRedirectPromise()&&s.enableLogging&&console.log("[MSAL] Redirect authentication successful");let g=s.enableLogging||!1;i.addEventCallback(h=>{if(h.eventType===EventType.LOGIN_SUCCESS&&g){let d=h.payload;console.log("[MSAL] Login successful:",d.account?.username);}h.eventType===EventType.LOGIN_FAILURE&&console.error("[MSAL] Login failed:",h.error),h.eventType===EventType.LOGOUT_SUCCESS&&g&&console.log("[MSAL] Logout successful");}),p.current=i,Q=i,u(i),o&&o(i);}catch(c){throw console.error("[MSAL] Initialization failed:",c),c}})();},[]),typeof window>"u"?jsx(Fragment,{children:e||jsx("div",{children:"Loading authentication..."})}):n?jsx(MsalProvider,{instance:n,children:r}):jsx(Fragment,{children:e||jsx("div",{children:"Loading authentication..."})})}function A(r=["User.Read"]){let{instance:e,accounts:o,inProgress:s}=useMsal(),n=useAccount(o[0]||null),u=useMemo(()=>o.length>0,[o]),p=useCallback(async(a=r)=>{try{let t={scopes:a,prompt:"select_account"};await e.loginPopup(t);}catch(t){throw console.error("[MSAL] Login popup failed:",t),t}},[e,r]),l=useCallback(async(a=r)=>{try{let t={scopes:a,prompt:"select_account"};await e.loginRedirect(t);}catch(t){throw console.error("[MSAL] Login redirect failed:",t),t}},[e,r]),c=useCallback(async()=>{try{await e.logoutPopup({account:n||void 0});}catch(a){throw console.error("[MSAL] Logout popup failed:",a),a}},[e,n]),i=useCallback(async()=>{try{await e.logoutRedirect({account:n||void 0});}catch(a){throw console.error("[MSAL] Logout redirect failed:",a),a}},[e,n]),f=useCallback(async(a=r)=>{if(!n)throw new Error("[MSAL] No active account. Please login first.");try{let t={scopes:a,account:n,forceRefresh:!1};return (await e.acquireTokenSilent(t)).accessToken}catch(t){throw console.error("[MSAL] Silent token acquisition failed:",t),t}},[e,n,r]),g=useCallback(async(a=r)=>{if(!n)throw new Error("[MSAL] No active account. Please login first.");try{let t={scopes:a,account:n};return (await e.acquireTokenPopup(t)).accessToken}catch(t){throw console.error("[MSAL] Token popup acquisition failed:",t),t}},[e,n,r]),h=useCallback(async(a=r)=>{if(!n)throw new Error("[MSAL] No active account. Please login first.");try{let t={scopes:a,account:n};await e.acquireTokenRedirect(t);}catch(t){throw console.error("[MSAL] Token redirect acquisition failed:",t),t}},[e,n,r]),d=useCallback(async(a=r)=>{try{return await f(a)}catch{return console.warn("[MSAL] Silent token acquisition failed, falling back to popup"),await g(a)}},[f,g,r]),m=useCallback(async()=>{e.setActiveAccount(null),await e.clearCache();},[e]);return {account:n,accounts:o,isAuthenticated:u,inProgress:s!==InteractionStatus.None,loginPopup:p,loginRedirect:l,logoutPopup:c,logoutRedirect:i,acquireToken:d,acquireTokenSilent:f,acquireTokenPopup:g,acquireTokenRedirect:h,clearSession:m}}function ye({text:r="Sign in with Microsoft",variant:e="dark",size:o="medium",useRedirect:s=false,scopes:n,className:u="",style:p,onSuccess:l,onError:c}){let{loginPopup:i,loginRedirect:f,inProgress:g}=A(),h=async()=>{try{s?await f(n):await i(n),l?.();}catch(t){c?.(t);}},d={small:{padding:"8px 16px",fontSize:"14px",height:"36px"},medium:{padding:"10px 20px",fontSize:"15px",height:"41px"},large:{padding:"12px 24px",fontSize:"16px",height:"48px"}},a={display:"inline-flex",alignItems:"center",justifyContent:"center",gap:"12px",fontFamily:'"Segoe UI", Tahoma, Geneva, Verdana, sans-serif',fontWeight:600,borderRadius:"2px",cursor:g?"not-allowed":"pointer",transition:"all 0.2s ease",opacity:g?.6:1,...{dark:{backgroundColor:"#2F2F2F",color:"#FFFFFF",border:"1px solid #8C8C8C"},light:{backgroundColor:"#FFFFFF",color:"#5E5E5E",border:"1px solid #8C8C8C"}}[e],...d[o],...p};return jsxs("button",{onClick:h,disabled:g,className:u,style:a,"aria-label":r,children:[jsx(Ae,{}),jsx("span",{children:r})]})}function Ae(){return jsxs("svg",{width:"21",height:"21",viewBox:"0 0 21 21",fill:"none",xmlns:"http://www.w3.org/2000/svg",children:[jsx("rect",{width:"10",height:"10",fill:"#F25022"}),jsx("rect",{x:"11",width:"10",height:"10",fill:"#7FBA00"}),jsx("rect",{y:"11",width:"10",height:"10",fill:"#00A4EF"}),jsx("rect",{x:"11",y:"11",width:"10",height:"10",fill:"#FFB900"})]})}function be({text:r="Sign out",variant:e="dark",size:o="medium",useRedirect:s=false,className:n="",style:u,onSuccess:p,onError:l}){let{logoutPopup:c,logoutRedirect:i,inProgress:f}=A(),g=async()=>{try{s?await i():await c(),p?.();}catch(a){l?.(a);}},h={small:{padding:"8px 16px",fontSize:"14px",height:"36px"},medium:{padding:"10px 20px",fontSize:"15px",height:"41px"},large:{padding:"12px 24px",fontSize:"16px",height:"48px"}},m={display:"inline-flex",alignItems:"center",justifyContent:"center",gap:"12px",fontFamily:'"Segoe UI", Tahoma, Geneva, Verdana, sans-serif',fontWeight:600,borderRadius:"2px",cursor:f?"not-allowed":"pointer",transition:"all 0.2s ease",opacity:f?.6:1,...{dark:{backgroundColor:"#2F2F2F",color:"#FFFFFF",border:"1px solid #8C8C8C"},light:{backgroundColor:"#FFFFFF",color:"#5E5E5E",border:"1px solid #8C8C8C"}}[e],...h[o],...u};return jsxs("button",{onClick:g,disabled:f,className:n,style:m,"aria-label":r,children:[jsx(xe,{}),jsx("span",{children:r})]})}function xe(){return jsxs("svg",{width:"21",height:"21",viewBox:"0 0 21 21",fill:"none",xmlns:"http://www.w3.org/2000/svg",children:[jsx("rect",{width:"10",height:"10",fill:"#F25022"}),jsx("rect",{x:"11",width:"10",height:"10",fill:"#7FBA00"}),jsx("rect",{y:"11",width:"10",height:"10",fill:"#00A4EF"}),jsx("rect",{x:"11",y:"11",width:"10",height:"10",fill:"#FFB900"})]})}function T(){let{acquireToken:r}=A(),e=useCallback(async(l,c={})=>{let{scopes:i=["User.Read"],version:f="v1.0",debug:g=false,...h}=c;try{let d=await r(i),m=`https://graph.microsoft.com/${f}`,a=l.startsWith("http")?l:`${m}${l.startsWith("/")?l:`/${l}`}`;g&&console.log("[GraphAPI] Request:",{url:a,method:h.method||"GET"});let t=await fetch(a,{...h,headers:{Authorization:`Bearer ${d}`,"Content-Type":"application/json",...h.headers}});if(!t.ok){let U=await t.text();throw new Error(`Graph API error (${t.status}): ${U}`)}if(t.status===204||t.headers.get("content-length")==="0")return null;let y=await t.json();return g&&console.log("[GraphAPI] Response:",y),y}catch(d){throw console.error("[GraphAPI] Request failed:",d),d}},[r]),o=useCallback((l,c={})=>e(l,{...c,method:"GET"}),[e]),s=useCallback((l,c,i={})=>e(l,{...i,method:"POST",body:c?JSON.stringify(c):void 0}),[e]),n=useCallback((l,c,i={})=>e(l,{...i,method:"PUT",body:c?JSON.stringify(c):void 0}),[e]),u=useCallback((l,c,i={})=>e(l,{...i,method:"PATCH",body:c?JSON.stringify(c):void 0}),[e]),p=useCallback((l,c={})=>e(l,{...c,method:"DELETE"}),[e]);return {get:o,post:s,put:n,patch:u,delete:p,request:e}}var q=new Map,ve=300*1e3;function B(){let{isAuthenticated:r,account:e}=A(),o=T(),[s,n]=useState(null),[u,p]=useState(false),[l,c]=useState(null),i=useCallback(async()=>{if(!r||!e){n(null);return}let g=e.homeAccountId,h=q.get(g);if(h&&Date.now()-h.timestamp<ve){n(h.data);return}p(true),c(null);try{let d=await o.get("/me",{scopes:["User.Read"]}),m;try{let t=await o.get("/me/photo/$value",{scopes:["User.Read"],headers:{"Content-Type":"image/jpeg"}});t&&(m=URL.createObjectURL(t));}catch{console.debug("[UserProfile] Photo not available");}let a={id:d.id,displayName:d.displayName,givenName:d.givenName,surname:d.surname,userPrincipalName:d.userPrincipalName,mail:d.mail,jobTitle:d.jobTitle,officeLocation:d.officeLocation,mobilePhone:d.mobilePhone,businessPhones:d.businessPhones,photo:m};q.set(g,{data:a,timestamp:Date.now()}),n(a);}catch(d){let m=d;c(m),console.error("[UserProfile] Failed to fetch profile:",m);}finally{p(false);}},[r,e,o]),f=useCallback(()=>{e&&q.delete(e.homeAccountId),n(null);},[e]);return useEffect(()=>{i();},[i]),{profile:s,loading:u,error:l,refetch:i,clearCache:f}}function Re({size:r=40,className:e="",style:o,showTooltip:s=true,fallbackImage:n}){let{profile:u,loading:p}=B(),[l,c]=useState(null),[i,f]=useState(false);useEffect(()=>{u?.photo&&c(u.photo);},[u?.photo]);let g=()=>{if(!u)return "?";let{givenName:m,surname:a,displayName:t}=u;if(m&&a)return `${m[0]}${a[0]}`.toUpperCase();if(t){let y=t.split(" ");return y.length>=2?`${y[0][0]}${y[y.length-1][0]}`.toUpperCase():t.substring(0,2).toUpperCase()}return "?"},h={width:`${r}px`,height:`${r}px`,borderRadius:"50%",display:"inline-flex",alignItems:"center",justifyContent:"center",fontSize:`${r*.4}px`,fontWeight:600,fontFamily:'"Segoe UI", Tahoma, Geneva, Verdana, sans-serif',backgroundColor:"#0078D4",color:"#FFFFFF",overflow:"hidden",userSelect:"none",...o},d=u?.displayName||"User";return p?jsx("div",{className:e,style:{...h,backgroundColor:"#E1E1E1"},"aria-label":"Loading user avatar",children:jsx("span",{style:{fontSize:`${r*.3}px`},children:"..."})}):l&&!i?jsx("div",{className:e,style:h,title:s?d:void 0,"aria-label":`${d} avatar`,children:jsx("img",{src:l,alt:d,style:{width:"100%",height:"100%",objectFit:"cover"},onError:()=>{f(true),n&&c(n);}})}):jsx("div",{className:e,style:h,title:s?d:void 0,"aria-label":`${d} avatar`,children:g()})}function Ce({className:r="",style:e,showDetails:o=false,renderLoading:s,renderAuthenticated:n,renderUnauthenticated:u}){let{isAuthenticated:p,inProgress:l,account:c}=A(),i={display:"inline-flex",alignItems:"center",gap:"8px",padding:"8px 12px",borderRadius:"4px",fontFamily:'"Segoe UI", Tahoma, Geneva, Verdana, sans-serif',fontSize:"14px",fontWeight:500,...e};if(l)return s?jsx(Fragment,{children:s()}):jsxs("div",{className:r,style:{...i,backgroundColor:"#FFF4CE",color:"#8A6D3B"},role:"status","aria-live":"polite",children:[jsx($,{color:"#FFA500"}),jsx("span",{children:"Loading..."})]});if(p){let f=c?.username||c?.name||"User";return n?jsx(Fragment,{children:n(f)}):jsxs("div",{className:r,style:{...i,backgroundColor:"#D4EDDA",color:"#155724"},role:"status","aria-live":"polite",children:[jsx($,{color:"#28A745"}),jsx("span",{children:o?`Authenticated as ${f}`:"Authenticated"})]})}return u?jsx(Fragment,{children:u()}):jsxs("div",{className:r,style:{...i,backgroundColor:"#F8D7DA",color:"#721C24"},role:"status","aria-live":"polite",children:[jsx($,{color:"#DC3545"}),jsx("span",{children:"Not authenticated"})]})}function $({color:r}){return jsx("svg",{width:"8",height:"8",viewBox:"0 0 8 8",fill:"none",xmlns:"http://www.w3.org/2000/svg",children:jsx("circle",{cx:"4",cy:"4",r:"4",fill:r})})}function _({children:r,loadingComponent:e,fallbackComponent:o,useRedirect:s=true,scopes:n,onAuthRequired:u}){let{isAuthenticated:p,inProgress:l,loginRedirect:c,loginPopup:i}=A();return useEffect(()=>{!p&&!l&&(u?.(),(async()=>{try{s?await c(n):await i(n);}catch(g){console.error("[AuthGuard] Authentication failed:",g);}})());},[p,l,s,n,c,i,u]),l?jsx(Fragment,{children:e||jsx("div",{children:"Authenticating..."})}):p?jsx(Fragment,{children:r}):jsx(Fragment,{children:o||jsx("div",{children:"Redirecting to login..."})})}var j=class extends Component{constructor(o){super(o);this.reset=()=>{this.setState({hasError:false,error:null});};this.state={hasError:false,error:null};}static getDerivedStateFromError(o){return {hasError:true,error:o}}componentDidCatch(o,s){let{onError:n,debug:u}=this.props;u&&(console.error("[ErrorBoundary] Caught error:",o),console.error("[ErrorBoundary] Error info:",s)),n?.(o,s);}render(){let{hasError:o,error:s}=this.state,{children:n,fallback:u}=this.props;return o&&s?u?u(s,this.reset):jsxs("div",{style:{padding:"20px",margin:"20px",border:"1px solid #DC3545",borderRadius:"4px",backgroundColor:"#F8D7DA",color:"#721C24",fontFamily:'"Segoe UI", Tahoma, Geneva, Verdana, sans-serif'},children:[jsx("h2",{style:{margin:"0 0 10px 0",fontSize:"18px"},children:"Authentication Error"}),jsx("p",{style:{margin:"0 0 10px 0"},children:s.message}),jsx("button",{onClick:this.reset,style:{padding:"8px 16px",backgroundColor:"#DC3545",color:"#FFFFFF",border:"none",borderRadius:"4px",cursor:"pointer",fontSize:"14px",fontWeight:600},children:"Try Again"})]}):n}};var re=new Map,ke=300*1e3;function Le(){let{isAuthenticated:r,account:e}=A(),o=T(),[s,n]=useState([]),[u,p]=useState([]),[l,c]=useState(false),[i,f]=useState(null),g=useCallback(async()=>{if(!r||!e){n([]),p([]);return}let t=e.homeAccountId,y=re.get(t);if(y&&Date.now()-y.timestamp<ke){n(y.roles),p(y.groups);return}c(true),f(null);try{let C=e.idTokenClaims?.roles||[],F=(await o.get("/me/memberOf",{scopes:["User.Read","Directory.Read.All"]})).value.map(ie=>ie.id);re.set(t,{roles:C,groups:F,timestamp:Date.now()}),n(C),p(F);}catch(U){let C=U;f(C),console.error("[Roles] Failed to fetch roles/groups:",C);let F=e.idTokenClaims?.roles||[];n(F);}finally{c(false);}},[r,e,o]),h=useCallback(t=>s.includes(t),[s]),d=useCallback(t=>u.includes(t),[u]),m=useCallback(t=>t.some(y=>s.includes(y)),[s]),a=useCallback(t=>t.every(y=>s.includes(y)),[s]);return useEffect(()=>{g();},[g]),{roles:s,groups:u,loading:l,error:i,hasRole:h,hasGroup:d,hasAnyRole:m,hasAllRoles:a,refetch:g}}function Ue(r,e={}){let{displayName:o,...s}=e,n=u=>jsx(_,{...s,children:jsx(r,{...u})});return n.displayName=o||`withAuth(${r.displayName||r.name||"Component"})`,n}async function oe(r,e={}){let{maxRetries:o=3,initialDelay:s=1e3,maxDelay:n=1e4,backoffMultiplier:u=2,debug:p=false}=e,l,c=s;for(let i=0;i<=o;i++)try{return p&&i>0&&console.log(`[TokenRetry] Attempt ${i+1}/${o+1}`),await r()}catch(f){if(l=f,i===o){p&&console.error("[TokenRetry] All retry attempts failed");break}if(!Fe(f))throw p&&console.log("[TokenRetry] Non-retryable error, aborting"),f;p&&console.warn(`[TokenRetry] Attempt ${i+1} failed, retrying in ${c}ms...`),await Ne(c),c=Math.min(c*u,n);}throw l}function Fe(r){let e=r.message.toLowerCase();return !!(e.includes("network")||e.includes("timeout")||e.includes("fetch")||e.includes("connection")||e.includes("500")||e.includes("502")||e.includes("503")||e.includes("429")||e.includes("rate limit")||e.includes("token")&&e.includes("expired"))}function Ne(r){return new Promise(e=>setTimeout(e,r))}function Ie(r,e={}){return (...o)=>oe(()=>r(...o),e)}var I=class{constructor(e={}){this.config={enabled:e.enabled??false,prefix:e.prefix??"[MSAL-Next]",showTimestamp:e.showTimestamp??true,level:e.level??"info"};}shouldLog(e){if(!this.config.enabled)return false;let o=["error","warn","info","debug"],s=o.indexOf(this.config.level);return o.indexOf(e)<=s}formatMessage(e,o,s){let n=this.config.showTimestamp?`[${new Date().toISOString()}]`:"",u=this.config.prefix,p=`[${e.toUpperCase()}]`,l=`${n} ${u} ${p} ${o}`;return s!==void 0&&(l+=`
|
|
2
|
+
`+JSON.stringify(s,null,2)),l}error(e,o){this.shouldLog("error")&&console.error(this.formatMessage("error",e,o));}warn(e,o){this.shouldLog("warn")&&console.warn(this.formatMessage("warn",e,o));}info(e,o){this.shouldLog("info")&&console.info(this.formatMessage("info",e,o));}debug(e,o){this.shouldLog("debug")&&console.debug(this.formatMessage("debug",e,o));}group(e){this.config.enabled&&console.group(`${this.config.prefix} ${e}`);}groupEnd(){this.config.enabled&&console.groupEnd();}setEnabled(e){this.config.enabled=e;}setLevel(e){e&&(this.config.level=e);}},L=null;function Ge(r){return L?r&&(r.enabled!==void 0&&L.setEnabled(r.enabled),r.level&&L.setLevel(r.level)):L=new I(r),L}function Oe(r,e){return new I({...e,prefix:`[MSAL-Next:${r}]`})}function De(r={}){let{protectedRoutes:e=[],publicOnlyRoutes:o=[],loginPath:s="/login",redirectAfterLogin:n="/",sessionCookie:u="msal.account",isAuthenticated:p,debug:l=false}=r;return async function(i){let{pathname:f}=i.nextUrl;l&&console.log("[AuthMiddleware] Processing:",f);let g=false;p?g=await p(i):g=!!i.cookies.get(u)?.value,l&&console.log("[AuthMiddleware] Authenticated:",g);let h=e.some(a=>f.startsWith(a)),d=o.some(a=>f.startsWith(a));if(h&&!g){l&&console.log("[AuthMiddleware] Redirecting to login");let a=i.nextUrl.clone();return a.pathname=s,a.searchParams.set("returnUrl",f),NextResponse.redirect(a)}if(d&&g){l&&console.log("[AuthMiddleware] Redirecting to home");let a=i.nextUrl.searchParams.get("returnUrl"),t=i.nextUrl.clone();return t.pathname=a||n,t.searchParams.delete("returnUrl"),NextResponse.redirect(t)}let m=NextResponse.next();if(g){m.headers.set("x-msal-authenticated","true");try{let a=i.cookies.get(u);if(a?.value){let t=JSON.parse(a.value);t.username&&m.headers.set("x-msal-username",t.username);}}catch{}}return m}}export{_ as AuthGuard,Ce as AuthStatus,j as ErrorBoundary,ye as MicrosoftSignInButton,de as MsalAuthProvider,be as SignOutButton,Re as UserAvatar,De as createAuthMiddleware,G as createMsalConfig,Ie as createRetryWrapper,Oe as createScopedLogger,Ge as getDebugLogger,pe as getMsalInstance,oe as retryWithBackoff,T as useGraphApi,A as useMsalAuth,Le as useRoles,B as useUserProfile,Ue as withAuth};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
interface ServerSession {
|
|
2
|
+
/**
|
|
3
|
+
* Whether user is authenticated
|
|
4
|
+
*/
|
|
5
|
+
isAuthenticated: boolean;
|
|
6
|
+
/**
|
|
7
|
+
* User's account ID from MSAL cache
|
|
8
|
+
*/
|
|
9
|
+
accountId?: string;
|
|
10
|
+
/**
|
|
11
|
+
* User's username/email
|
|
12
|
+
*/
|
|
13
|
+
username?: string;
|
|
14
|
+
/**
|
|
15
|
+
* Access token (if available in cookie)
|
|
16
|
+
*/
|
|
17
|
+
accessToken?: string;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Server-side session helper for Next.js App Router
|
|
21
|
+
*
|
|
22
|
+
* Note: This is a basic implementation that reads from cookies.
|
|
23
|
+
* For production use, consider implementing a proper session store.
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```tsx
|
|
27
|
+
* // In a Server Component or Route Handler
|
|
28
|
+
* import { getServerSession } from '@chemmangat/msal-next';
|
|
29
|
+
*
|
|
30
|
+
* export default async function Page() {
|
|
31
|
+
* const session = await getServerSession();
|
|
32
|
+
*
|
|
33
|
+
* if (!session.isAuthenticated) {
|
|
34
|
+
* redirect('/login');
|
|
35
|
+
* }
|
|
36
|
+
*
|
|
37
|
+
* return <div>Welcome {session.username}</div>;
|
|
38
|
+
* }
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
declare function getServerSession(): Promise<ServerSession>;
|
|
42
|
+
/**
|
|
43
|
+
* Helper to set server session in cookies (call from client-side after auth)
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```tsx
|
|
47
|
+
* // After successful login
|
|
48
|
+
* await setServerSessionCookie(account, accessToken);
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
declare function setServerSessionCookie(account: any, accessToken?: string): Promise<void>;
|
|
52
|
+
|
|
53
|
+
export { type ServerSession, getServerSession, setServerSessionCookie };
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
interface ServerSession {
|
|
2
|
+
/**
|
|
3
|
+
* Whether user is authenticated
|
|
4
|
+
*/
|
|
5
|
+
isAuthenticated: boolean;
|
|
6
|
+
/**
|
|
7
|
+
* User's account ID from MSAL cache
|
|
8
|
+
*/
|
|
9
|
+
accountId?: string;
|
|
10
|
+
/**
|
|
11
|
+
* User's username/email
|
|
12
|
+
*/
|
|
13
|
+
username?: string;
|
|
14
|
+
/**
|
|
15
|
+
* Access token (if available in cookie)
|
|
16
|
+
*/
|
|
17
|
+
accessToken?: string;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Server-side session helper for Next.js App Router
|
|
21
|
+
*
|
|
22
|
+
* Note: This is a basic implementation that reads from cookies.
|
|
23
|
+
* For production use, consider implementing a proper session store.
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```tsx
|
|
27
|
+
* // In a Server Component or Route Handler
|
|
28
|
+
* import { getServerSession } from '@chemmangat/msal-next';
|
|
29
|
+
*
|
|
30
|
+
* export default async function Page() {
|
|
31
|
+
* const session = await getServerSession();
|
|
32
|
+
*
|
|
33
|
+
* if (!session.isAuthenticated) {
|
|
34
|
+
* redirect('/login');
|
|
35
|
+
* }
|
|
36
|
+
*
|
|
37
|
+
* return <div>Welcome {session.username}</div>;
|
|
38
|
+
* }
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
declare function getServerSession(): Promise<ServerSession>;
|
|
42
|
+
/**
|
|
43
|
+
* Helper to set server session in cookies (call from client-side after auth)
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```tsx
|
|
47
|
+
* // After successful login
|
|
48
|
+
* await setServerSessionCookie(account, accessToken);
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
declare function setServerSessionCookie(account: any, accessToken?: string): Promise<void>;
|
|
52
|
+
|
|
53
|
+
export { type ServerSession, getServerSession, setServerSessionCookie };
|
package/dist/server.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
'use strict';var headers=require('next/headers');async function i(){try{let e=await headers.cookies(),r=await headers.headers(),t=e.get("msal.account"),o=e.get("msal.token");if(t?.value)try{let s=JSON.parse(t.value);return {isAuthenticated:!0,accountId:s.homeAccountId,username:s.username,accessToken:o?.value}}catch(s){console.error("[ServerSession] Failed to parse account data:",s);}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 c(e,r){try{let t={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:t,token:r})});}catch(t){console.error("[ServerSession] Failed to set session cookie:",t);}}exports.getServerSession=i;exports.setServerSessionCookie=c;
|
package/dist/server.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import {cookies,headers}from'next/headers';async function i(){try{let e=await cookies(),r=await headers(),t=e.get("msal.account"),o=e.get("msal.token");if(t?.value)try{let s=JSON.parse(t.value);return {isAuthenticated:!0,accountId:s.homeAccountId,username:s.username,accessToken:o?.value}}catch(s){console.error("[ServerSession] Failed to parse account data:",s);}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 c(e,r){try{let t={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:t,token:r})});}catch(t){console.error("[ServerSession] Failed to set session cookie:",t);}}export{i as getServerSession,c as setServerSessionCookie};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@chemmangat/msal-next",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "2.1.0",
|
|
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",
|
|
7
7
|
"types": "./dist/index.d.ts",
|
|
@@ -10,6 +10,11 @@
|
|
|
10
10
|
"types": "./dist/index.d.ts",
|
|
11
11
|
"import": "./dist/index.mjs",
|
|
12
12
|
"require": "./dist/index.js"
|
|
13
|
+
},
|
|
14
|
+
"./server": {
|
|
15
|
+
"types": "./dist/server.d.ts",
|
|
16
|
+
"import": "./dist/server.mjs",
|
|
17
|
+
"require": "./dist/server.js"
|
|
13
18
|
}
|
|
14
19
|
},
|
|
15
20
|
"files": [
|
|
@@ -19,6 +24,9 @@
|
|
|
19
24
|
"scripts": {
|
|
20
25
|
"build": "tsup",
|
|
21
26
|
"dev": "tsup --watch",
|
|
27
|
+
"test": "vitest run",
|
|
28
|
+
"test:watch": "vitest",
|
|
29
|
+
"test:coverage": "vitest run --coverage",
|
|
22
30
|
"prepublishOnly": "npm run build"
|
|
23
31
|
},
|
|
24
32
|
"keywords": [
|
|
@@ -30,7 +38,9 @@
|
|
|
30
38
|
"oauth",
|
|
31
39
|
"next.js",
|
|
32
40
|
"app-router",
|
|
33
|
-
"typescript"
|
|
41
|
+
"typescript",
|
|
42
|
+
"sso",
|
|
43
|
+
"microsoft-graph"
|
|
34
44
|
],
|
|
35
45
|
"author": "Chemmangat",
|
|
36
46
|
"license": "MIT",
|
|
@@ -53,9 +63,14 @@
|
|
|
53
63
|
"devDependencies": {
|
|
54
64
|
"@azure/msal-browser": "^3.11.1",
|
|
55
65
|
"@azure/msal-react": "^2.0.15",
|
|
66
|
+
"@testing-library/react": "^14.0.0",
|
|
67
|
+
"@testing-library/react-hooks": "^8.0.1",
|
|
56
68
|
"@types/react": "^18.2.0",
|
|
69
|
+
"@vitest/coverage-v8": "^1.0.0",
|
|
70
|
+
"jsdom": "^23.0.0",
|
|
57
71
|
"react": "^18.2.0",
|
|
58
72
|
"tsup": "^8.0.1",
|
|
59
|
-
"typescript": "^5.3.0"
|
|
73
|
+
"typescript": "^5.3.0",
|
|
74
|
+
"vitest": "^1.0.0"
|
|
60
75
|
}
|
|
61
76
|
}
|
package/dist/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/components/MsalAuthProvider.tsx","../src/utils/createMsalConfig.ts","../src/hooks/useMsalAuth.ts","../src/components/MicrosoftSignInButton.tsx"],"sourcesContent":["export { MsalAuthProvider, getMsalInstance } from './components/MsalAuthProvider';\r\nexport { MicrosoftSignInButton } from './components/MicrosoftSignInButton';\r\nexport { useMsalAuth } from './hooks/useMsalAuth';\r\nexport type { UseMsalAuthReturn } from './hooks/useMsalAuth';\r\nexport type { MsalAuthConfig, MsalAuthProviderProps } from './types';\r\nexport type { MicrosoftSignInButtonProps } from './components/MicrosoftSignInButton';\r\n\r\n// Re-export useful MSAL hooks\r\nexport { useMsal, useIsAuthenticated, useAccount } from '@azure/msal-react';\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","import { Configuration, LogLevel } from '@azure/msal-browser';\r\nimport { MsalAuthConfig } from '../types';\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 } = 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 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 { useMsal, useAccount } from '@azure/msal-react';\r\nimport { AccountInfo, InteractionStatus, PopupRequest, RedirectRequest, SilentRequest } from '@azure/msal-browser';\r\nimport { useCallback, useMemo } 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\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\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 };\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 try {\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 }\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 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 }\r\n },\r\n [acquireTokenSilent, acquireTokenPopup, defaultScopes]\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"],"mappings":"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","names":["import_msal_browser","import_msal_react","import_msal_browser","import_react","import_jsx_runtime","import_msal_react"]}
|