@chemmangat/msal-next 5.0.0 → 5.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +86 -0
- package/README.md +82 -1
- package/dist/index.d.mts +183 -76
- package/dist/index.d.ts +183 -76
- package/dist/index.js +258 -24
- package/dist/index.mjs +241 -9
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,92 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [5.1.0] - 2026-03-17
|
|
6
|
+
|
|
7
|
+
### ✨ New Features
|
|
8
|
+
|
|
9
|
+
#### 1. Multi-Tenant Support — `multiTenant` config
|
|
10
|
+
|
|
11
|
+
Pass a `multiTenant` object to `MSALProvider` to control which tenants can access your app:
|
|
12
|
+
|
|
13
|
+
```tsx
|
|
14
|
+
<MSALProvider
|
|
15
|
+
clientId="..."
|
|
16
|
+
multiTenant={{
|
|
17
|
+
type: 'multi', // 'single' | 'multi' | 'organizations' | 'consumers' | 'common'
|
|
18
|
+
allowList: ['contoso.com', 'fabrikam.com'],
|
|
19
|
+
blockList: ['competitor.com'],
|
|
20
|
+
requireType: 'Member', // block B2B guests
|
|
21
|
+
requireMFA: true,
|
|
22
|
+
}}
|
|
23
|
+
onTenantDenied={(reason) => router.push(`/denied?reason=${reason}`)}
|
|
24
|
+
>
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
- `type` maps to the MSAL authority (`single` → tenant, `multi`/`common` → common, etc.)
|
|
28
|
+
- `allowList` / `blockList` accept tenant IDs or domain names
|
|
29
|
+
- `requireType: 'Member'` blocks B2B guests; `'Guest'` allows only guests
|
|
30
|
+
- `requireMFA` checks the `amr` claim for MFA evidence
|
|
31
|
+
- Tenant validation runs automatically after redirect authentication
|
|
32
|
+
|
|
33
|
+
#### 2. `useTenant()` Hook
|
|
34
|
+
|
|
35
|
+
```tsx
|
|
36
|
+
import { useTenant } from '@chemmangat/msal-next';
|
|
37
|
+
|
|
38
|
+
const { tenantId, tenantDomain, isGuestUser, homeTenantId, resourceTenantId, claims } = useTenant();
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Returns tenant context for the current user including B2B guest detection.
|
|
42
|
+
|
|
43
|
+
#### 3. Per-Page Tenant Restrictions
|
|
44
|
+
|
|
45
|
+
```tsx
|
|
46
|
+
// app/admin/page.tsx
|
|
47
|
+
export const auth = {
|
|
48
|
+
required: true,
|
|
49
|
+
tenant: {
|
|
50
|
+
allowList: ['contoso.com'],
|
|
51
|
+
requireMFA: true,
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
#### 4. Middleware Tenant Validation
|
|
57
|
+
|
|
58
|
+
```ts
|
|
59
|
+
// middleware.ts
|
|
60
|
+
export const middleware = createAuthMiddleware({
|
|
61
|
+
protectedRoutes: ['/dashboard'],
|
|
62
|
+
tenantConfig: { allowList: ['contoso.com'] },
|
|
63
|
+
tenantDeniedPath: '/unauthorized',
|
|
64
|
+
});
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
#### 5. Cross-Tenant Token Acquisition
|
|
68
|
+
|
|
69
|
+
```tsx
|
|
70
|
+
const { acquireTokenForTenant } = useMsalAuth();
|
|
71
|
+
const token = await acquireTokenForTenant('target-tenant-id', ['User.Read']);
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
#### 6. `useTenantConfig()` Hook
|
|
75
|
+
|
|
76
|
+
Access the `multiTenant` config from anywhere in the component tree:
|
|
77
|
+
|
|
78
|
+
```tsx
|
|
79
|
+
import { useTenantConfig } from '@chemmangat/msal-next';
|
|
80
|
+
const config = useTenantConfig();
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### 🔧 Internal
|
|
84
|
+
|
|
85
|
+
- `createMsalConfig` now maps `multiTenant.type` to the correct MSAL authority (takes precedence over legacy `authorityType`)
|
|
86
|
+
- `validateTenantAccess` utility exported for advanced use cases
|
|
87
|
+
- `TenantAuthConfig` type exported for per-page tenant config
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
5
91
|
## [5.0.0] - 2026-03-16
|
|
6
92
|
|
|
7
93
|
### ⚠️ Breaking Changes
|
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@ Microsoft/Azure AD authentication for Next.js App Router. Minimal setup, full Ty
|
|
|
6
6
|
[](https://opensource.org/licenses/MIT)
|
|
7
7
|
[](./SECURITY.md)
|
|
8
8
|
|
|
9
|
-
**Current version:
|
|
9
|
+
**Current version: 5.1.0**
|
|
10
10
|
|
|
11
11
|
---
|
|
12
12
|
|
|
@@ -16,6 +16,20 @@ Microsoft/Azure AD authentication for Next.js App Router. Minimal setup, full Ty
|
|
|
16
16
|
npm install @chemmangat/msal-next @azure/msal-browser @azure/msal-react
|
|
17
17
|
```
|
|
18
18
|
|
|
19
|
+
Or scaffold everything automatically with the CLI (Node.js 18+ required):
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npx @chemmangat/msal-next-cli init
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
The `init` command interactively asks for your client ID, tenant ID, authority type, and cache location, then creates `.env.local`, updates `app/layout.tsx` with `MSALProvider`, and generates a starter `app/auth/page.tsx`.
|
|
26
|
+
|
|
27
|
+
To migrate an existing project from popup-based auth to redirect:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
npx @chemmangat/msal-next-cli migrate
|
|
31
|
+
```
|
|
32
|
+
|
|
19
33
|
---
|
|
20
34
|
|
|
21
35
|
## Quick Start
|
|
@@ -179,6 +193,12 @@ Protects content and redirects unauthenticated users to login.
|
|
|
179
193
|
onSwitch={(account) => {}}
|
|
180
194
|
onAdd={() => {}}
|
|
181
195
|
onRemove={(account) => {}}
|
|
196
|
+
// v5.0.0 — custom account row rendering
|
|
197
|
+
renderAccount={(account, isActive) => (
|
|
198
|
+
<div style={{ fontWeight: isActive ? 'bold' : 'normal' }}>
|
|
199
|
+
{account.name} ({account.username})
|
|
200
|
+
</div>
|
|
201
|
+
)}
|
|
182
202
|
/>
|
|
183
203
|
```
|
|
184
204
|
|
|
@@ -192,11 +212,71 @@ Protects content and redirects unauthenticated users to login.
|
|
|
192
212
|
clickToSwitch
|
|
193
213
|
orientation="vertical" // 'vertical' | 'horizontal'
|
|
194
214
|
onAccountClick={(account) => {}}
|
|
215
|
+
// v5.0.0 — custom account row rendering
|
|
216
|
+
renderAccount={(account, isActive) => (
|
|
217
|
+
<div style={{ color: isActive ? 'blue' : 'black' }}>
|
|
218
|
+
{account.name} — {account.username}
|
|
219
|
+
</div>
|
|
220
|
+
)}
|
|
195
221
|
/>
|
|
196
222
|
```
|
|
197
223
|
|
|
198
224
|
---
|
|
199
225
|
|
|
226
|
+
## Multi-Tenant Support (v5.1.0)
|
|
227
|
+
|
|
228
|
+
### Provider Configuration
|
|
229
|
+
|
|
230
|
+
```tsx
|
|
231
|
+
<MSALProvider
|
|
232
|
+
clientId={process.env.NEXT_PUBLIC_AZURE_AD_CLIENT_ID!}
|
|
233
|
+
multiTenant={{
|
|
234
|
+
type: 'multi',
|
|
235
|
+
allowList: ['contoso.com', 'fabrikam.com'],
|
|
236
|
+
blockList: ['competitor.com'],
|
|
237
|
+
requireType: 'Member',
|
|
238
|
+
requireMFA: true,
|
|
239
|
+
}}
|
|
240
|
+
onTenantDenied={(reason) => router.push(`/denied?reason=${encodeURIComponent(reason)}`)}
|
|
241
|
+
>
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
### `useTenant()` Hook
|
|
245
|
+
|
|
246
|
+
```tsx
|
|
247
|
+
import { useTenant } from '@chemmangat/msal-next';
|
|
248
|
+
|
|
249
|
+
const { tenantId, tenantDomain, isGuestUser, homeTenantId, resourceTenantId, claims } = useTenant();
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
### Per-Page Tenant Restrictions
|
|
253
|
+
|
|
254
|
+
```tsx
|
|
255
|
+
export const auth = {
|
|
256
|
+
required: true,
|
|
257
|
+
tenant: { allowList: ['contoso.com'], requireMFA: true },
|
|
258
|
+
};
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
### Middleware Tenant Validation
|
|
262
|
+
|
|
263
|
+
```ts
|
|
264
|
+
export const middleware = createAuthMiddleware({
|
|
265
|
+
protectedRoutes: ['/dashboard'],
|
|
266
|
+
tenantConfig: { allowList: ['contoso.com'] },
|
|
267
|
+
tenantDeniedPath: '/unauthorized',
|
|
268
|
+
});
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
### Cross-Tenant Token Acquisition
|
|
272
|
+
|
|
273
|
+
```tsx
|
|
274
|
+
const { acquireTokenForTenant } = useMsalAuth();
|
|
275
|
+
const token = await acquireTokenForTenant('target-tenant-id', ['User.Read']);
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
---
|
|
279
|
+
|
|
200
280
|
### Hooks
|
|
201
281
|
|
|
202
282
|
#### useMsalAuth()
|
|
@@ -213,6 +293,7 @@ const {
|
|
|
213
293
|
acquireTokenSilent, // (scopes: string[]) => Promise<string> — silent only
|
|
214
294
|
acquireTokenRedirect, // (scopes: string[]) => Promise<void>
|
|
215
295
|
clearSession, // () => Promise<void> — clears cache without Microsoft logout
|
|
296
|
+
acquireTokenForTenant,// (tenantId: string, scopes: string[]) => Promise<string> — cross-tenant (v5.1.0)
|
|
216
297
|
} = useMsalAuth();
|
|
217
298
|
```
|
|
218
299
|
|
package/dist/index.d.mts
CHANGED
|
@@ -292,13 +292,66 @@ interface MsalAuthConfig {
|
|
|
292
292
|
* Only used when autoRefreshToken is enabled.
|
|
293
293
|
*
|
|
294
294
|
* @defaultValue 300 (5 minutes)
|
|
295
|
+
*/
|
|
296
|
+
refreshBeforeExpiry?: number;
|
|
297
|
+
/**
|
|
298
|
+
* Multi-tenant configuration (v5.1.0)
|
|
299
|
+
*
|
|
300
|
+
* @remarks
|
|
301
|
+
* Controls which tenants are allowed to access the application and how
|
|
302
|
+
* cross-tenant token acquisition is handled.
|
|
295
303
|
*
|
|
296
304
|
* @example
|
|
297
305
|
* ```tsx
|
|
298
|
-
*
|
|
306
|
+
* <MSALProvider
|
|
307
|
+
* clientId="..."
|
|
308
|
+
* multiTenant={{
|
|
309
|
+
* type: 'multi',
|
|
310
|
+
* allowList: ['contoso.com', 'fabrikam.com'],
|
|
311
|
+
* requireMFA: true,
|
|
312
|
+
* }}
|
|
313
|
+
* >
|
|
299
314
|
* ```
|
|
300
315
|
*/
|
|
301
|
-
|
|
316
|
+
multiTenant?: MultiTenantConfig;
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* Multi-tenant configuration for v5.1.0
|
|
320
|
+
*/
|
|
321
|
+
interface MultiTenantConfig {
|
|
322
|
+
/**
|
|
323
|
+
* Tenant mode
|
|
324
|
+
* - 'single' — only your own tenant (maps to authorityType 'tenant')
|
|
325
|
+
* - 'multi' — any Azure AD tenant (maps to authorityType 'common')
|
|
326
|
+
* - 'organizations' — any organisational tenant, no personal accounts
|
|
327
|
+
* - 'consumers' — Microsoft personal accounts only
|
|
328
|
+
* - 'common' — alias for 'multi'
|
|
329
|
+
*
|
|
330
|
+
* @defaultValue 'common'
|
|
331
|
+
*/
|
|
332
|
+
type?: 'single' | 'multi' | 'organizations' | 'consumers' | 'common';
|
|
333
|
+
/**
|
|
334
|
+
* Tenant allow-list — only users from these tenant IDs or domains are permitted.
|
|
335
|
+
* Checked after authentication; users from other tenants are shown an error.
|
|
336
|
+
*
|
|
337
|
+
* @example ['contoso.com', '72f988bf-86f1-41af-91ab-2d7cd011db47']
|
|
338
|
+
*/
|
|
339
|
+
allowList?: string[];
|
|
340
|
+
/**
|
|
341
|
+
* Tenant block-list — users from these tenant IDs or domains are denied.
|
|
342
|
+
* Takes precedence over allowList.
|
|
343
|
+
*/
|
|
344
|
+
blockList?: string[];
|
|
345
|
+
/**
|
|
346
|
+
* Require a specific tenant type ('Member' | 'Guest').
|
|
347
|
+
* Useful to block B2B guests or to allow only guests.
|
|
348
|
+
*/
|
|
349
|
+
requireType?: 'Member' | 'Guest';
|
|
350
|
+
/**
|
|
351
|
+
* Require MFA claim in the token (amr claim must contain 'mfa').
|
|
352
|
+
* @defaultValue false
|
|
353
|
+
*/
|
|
354
|
+
requireMFA?: boolean;
|
|
302
355
|
}
|
|
303
356
|
/**
|
|
304
357
|
* Props for MsalAuthProvider component
|
|
@@ -318,13 +371,38 @@ interface MsalAuthProviderProps extends MsalAuthConfig {
|
|
|
318
371
|
* @returns The MSAL instance or null if not initialized
|
|
319
372
|
*/
|
|
320
373
|
declare function getMsalInstance(): PublicClientApplication | null;
|
|
321
|
-
declare function MsalAuthProvider({ children, loadingComponent, onInitialized, autoRefreshToken, refreshBeforeExpiry, ...config }: MsalAuthProviderProps
|
|
374
|
+
declare function MsalAuthProvider({ children, loadingComponent, onInitialized, autoRefreshToken, refreshBeforeExpiry, onTenantDenied, ...config }: MsalAuthProviderProps & {
|
|
375
|
+
onTenantDenied?: (reason: string) => void;
|
|
376
|
+
}): react_jsx_runtime.JSX.Element;
|
|
322
377
|
|
|
323
378
|
/**
|
|
324
379
|
* Zero-Config Protected Routes - Type Definitions
|
|
325
380
|
* v4.0.0 Killer Feature
|
|
326
381
|
*/
|
|
327
382
|
|
|
383
|
+
/**
|
|
384
|
+
* Per-page tenant access configuration (v5.1.0)
|
|
385
|
+
*/
|
|
386
|
+
interface TenantAuthConfig {
|
|
387
|
+
/**
|
|
388
|
+
* Only users from these tenant IDs or domains are permitted on this page.
|
|
389
|
+
* @example ['contoso.com', '72f988bf-86f1-41af-91ab-2d7cd011db47']
|
|
390
|
+
*/
|
|
391
|
+
allowList?: string[];
|
|
392
|
+
/**
|
|
393
|
+
* Users from these tenant IDs or domains are denied on this page.
|
|
394
|
+
* Takes precedence over allowList.
|
|
395
|
+
*/
|
|
396
|
+
blockList?: string[];
|
|
397
|
+
/**
|
|
398
|
+
* Require a specific account type ('Member' | 'Guest').
|
|
399
|
+
*/
|
|
400
|
+
requireType?: 'Member' | 'Guest';
|
|
401
|
+
/**
|
|
402
|
+
* Require MFA claim in the token (amr must contain 'mfa').
|
|
403
|
+
*/
|
|
404
|
+
requireMFA?: boolean;
|
|
405
|
+
}
|
|
328
406
|
/**
|
|
329
407
|
* Page-level auth configuration
|
|
330
408
|
* Export this from your page to enable protection
|
|
@@ -334,109 +412,81 @@ declare function MsalAuthProvider({ children, loadingComponent, onInitialized, a
|
|
|
334
412
|
* // app/dashboard/page.tsx
|
|
335
413
|
* export const auth = { required: true };
|
|
336
414
|
*
|
|
337
|
-
*
|
|
338
|
-
*
|
|
339
|
-
*
|
|
415
|
+
* // With tenant restriction (v5.1.0)
|
|
416
|
+
* export const auth = {
|
|
417
|
+
* required: true,
|
|
418
|
+
* tenant: { allowList: ['contoso.com'], requireMFA: true }
|
|
419
|
+
* };
|
|
340
420
|
* ```
|
|
341
421
|
*/
|
|
342
422
|
interface PageAuthConfig {
|
|
343
|
-
/**
|
|
344
|
-
* Whether authentication is required for this page
|
|
345
|
-
* @default false
|
|
346
|
-
*/
|
|
423
|
+
/** Whether authentication is required for this page */
|
|
347
424
|
required?: boolean;
|
|
348
425
|
/**
|
|
349
426
|
* Required roles for access (checks account.idTokenClaims.roles)
|
|
350
427
|
* User must have at least one of these roles
|
|
351
|
-
*
|
|
352
|
-
* @example
|
|
353
|
-
* ```tsx
|
|
354
|
-
* export const auth = {
|
|
355
|
-
* required: true,
|
|
356
|
-
* roles: ['admin', 'editor']
|
|
357
|
-
* };
|
|
358
|
-
* ```
|
|
359
428
|
*/
|
|
360
429
|
roles?: string[];
|
|
361
|
-
/**
|
|
362
|
-
* Custom redirect path when auth fails
|
|
363
|
-
* @default '/login'
|
|
364
|
-
*/
|
|
430
|
+
/** Custom redirect path when auth fails */
|
|
365
431
|
redirectTo?: string;
|
|
366
|
-
/**
|
|
367
|
-
* Custom loading component while checking auth
|
|
368
|
-
*/
|
|
432
|
+
/** Custom loading component while checking auth */
|
|
369
433
|
loading?: ReactNode;
|
|
370
|
-
/**
|
|
371
|
-
* Custom unauthorized component (shown instead of redirect)
|
|
372
|
-
*/
|
|
434
|
+
/** Custom unauthorized component (shown instead of redirect) */
|
|
373
435
|
unauthorized?: ReactNode;
|
|
374
436
|
/**
|
|
375
|
-
* Custom validation function
|
|
376
|
-
* Return true to allow access, false to deny
|
|
377
|
-
*
|
|
378
|
-
* @example
|
|
379
|
-
* ```tsx
|
|
380
|
-
* export const auth = {
|
|
381
|
-
* required: true,
|
|
382
|
-
* validate: (account) => account.username.endsWith('@company.com')
|
|
383
|
-
* };
|
|
384
|
-
* ```
|
|
437
|
+
* Custom validation function.
|
|
438
|
+
* Return true to allow access, false to deny.
|
|
385
439
|
*/
|
|
386
440
|
validate?: (account: any) => boolean | Promise<boolean>;
|
|
441
|
+
/**
|
|
442
|
+
* Per-page tenant access restrictions (v5.1.0).
|
|
443
|
+
* Checked after role validation.
|
|
444
|
+
*/
|
|
445
|
+
tenant?: TenantAuthConfig;
|
|
387
446
|
}
|
|
388
447
|
/**
|
|
389
448
|
* Global auth configuration for the provider
|
|
390
449
|
*/
|
|
391
450
|
interface AuthProtectionConfig {
|
|
392
|
-
/**
|
|
393
|
-
* Default redirect path for unauthenticated users
|
|
394
|
-
* @default '/login'
|
|
395
|
-
*/
|
|
451
|
+
/** Default redirect path for unauthenticated users */
|
|
396
452
|
defaultRedirectTo?: string;
|
|
397
|
-
/**
|
|
398
|
-
* Default loading component
|
|
399
|
-
*/
|
|
453
|
+
/** Default loading component */
|
|
400
454
|
defaultLoading?: ReactNode;
|
|
401
|
-
/**
|
|
402
|
-
* Default unauthorized component
|
|
403
|
-
*/
|
|
455
|
+
/** Default unauthorized component */
|
|
404
456
|
defaultUnauthorized?: ReactNode;
|
|
405
|
-
/**
|
|
406
|
-
* Enable debug logging
|
|
407
|
-
* @default false
|
|
408
|
-
*/
|
|
457
|
+
/** Enable debug logging */
|
|
409
458
|
debug?: boolean;
|
|
410
459
|
}
|
|
411
460
|
|
|
412
461
|
interface MSALProviderProps extends MsalAuthProviderProps {
|
|
413
462
|
/**
|
|
414
463
|
* Zero-Config Protected Routes configuration (v4.0.0)
|
|
415
|
-
* @example
|
|
416
|
-
* ```tsx
|
|
417
|
-
* <MSALProvider
|
|
418
|
-
* clientId="..."
|
|
419
|
-
* protection={{
|
|
420
|
-
* defaultRedirectTo: '/login',
|
|
421
|
-
* defaultLoading: <Spinner />,
|
|
422
|
-
* debug: true
|
|
423
|
-
* }}
|
|
424
|
-
* >
|
|
425
|
-
* ```
|
|
426
464
|
*/
|
|
427
465
|
protection?: AuthProtectionConfig;
|
|
466
|
+
/**
|
|
467
|
+
* Called when a user's tenant is denied access (v5.1.0)
|
|
468
|
+
*/
|
|
469
|
+
onTenantDenied?: (reason: string) => void;
|
|
428
470
|
}
|
|
471
|
+
/**
|
|
472
|
+
* Access the multi-tenant configuration from anywhere in the tree (v5.1.0).
|
|
473
|
+
*
|
|
474
|
+
* @example
|
|
475
|
+
* ```tsx
|
|
476
|
+
* const tenantConfig = useTenantConfig();
|
|
477
|
+
* console.log(tenantConfig?.allowList);
|
|
478
|
+
* ```
|
|
479
|
+
*/
|
|
480
|
+
declare function useTenantConfig(): MultiTenantConfig | undefined;
|
|
429
481
|
/**
|
|
430
482
|
* Pre-configured MSALProvider component for Next.js App Router layouts.
|
|
431
483
|
*
|
|
432
484
|
* @remarks
|
|
433
|
-
*
|
|
434
|
-
* and use it directly in your server-side layout.tsx without adding 'use client'
|
|
435
|
-
* to your layout file.
|
|
485
|
+
* Already marked as 'use client' internally — safe to import in server layouts.
|
|
436
486
|
*
|
|
437
487
|
* @example
|
|
438
488
|
* ```tsx
|
|
439
|
-
* // app/layout.tsx (Server Component
|
|
489
|
+
* // app/layout.tsx (Server Component)
|
|
440
490
|
* import { MSALProvider } from '@chemmangat/msal-next'
|
|
441
491
|
*
|
|
442
492
|
* export default function RootLayout({ children }) {
|
|
@@ -446,6 +496,7 @@ interface MSALProviderProps extends MsalAuthProviderProps {
|
|
|
446
496
|
* <MSALProvider
|
|
447
497
|
* clientId={process.env.NEXT_PUBLIC_AZURE_AD_CLIENT_ID!}
|
|
448
498
|
* tenantId={process.env.NEXT_PUBLIC_AZURE_AD_TENANT_ID!}
|
|
499
|
+
* multiTenant={{ type: 'multi', allowList: ['contoso.com'] }}
|
|
449
500
|
* >
|
|
450
501
|
* {children}
|
|
451
502
|
* </MSALProvider>
|
|
@@ -454,15 +505,8 @@ interface MSALProviderProps extends MsalAuthProviderProps {
|
|
|
454
505
|
* )
|
|
455
506
|
* }
|
|
456
507
|
* ```
|
|
457
|
-
*
|
|
458
|
-
* @security
|
|
459
|
-
* - All authentication happens client-side (browser)
|
|
460
|
-
* - Tokens are never sent to your Next.js server
|
|
461
|
-
* - Uses Microsoft's official MSAL library
|
|
462
|
-
* - Supports secure token storage (sessionStorage/localStorage)
|
|
463
|
-
* - No server-side token handling required
|
|
464
508
|
*/
|
|
465
|
-
declare function MSALProvider({ children, protection, ...props }: MSALProviderProps): react_jsx_runtime.JSX.Element;
|
|
509
|
+
declare function MSALProvider({ children, protection, onTenantDenied, ...props }: MSALProviderProps): react_jsx_runtime.JSX.Element;
|
|
466
510
|
|
|
467
511
|
interface MicrosoftSignInButtonProps {
|
|
468
512
|
/**
|
|
@@ -921,9 +965,62 @@ interface UseMsalAuthReturn {
|
|
|
921
965
|
* Clear MSAL session without triggering Microsoft logout
|
|
922
966
|
*/
|
|
923
967
|
clearSession: () => Promise<void>;
|
|
968
|
+
/**
|
|
969
|
+
* Acquire an access token for a specific tenant (cross-tenant, v5.1.0).
|
|
970
|
+
* Uses acquireTokenSilent with an explicit authority for the target tenant.
|
|
971
|
+
*/
|
|
972
|
+
acquireTokenForTenant: (tenantId: string, scopes: string[]) => Promise<string>;
|
|
924
973
|
}
|
|
925
974
|
declare function useMsalAuth(defaultScopes?: string[]): UseMsalAuthReturn;
|
|
926
975
|
|
|
976
|
+
interface TenantInfo {
|
|
977
|
+
/** The tenant ID from the current account's token claims */
|
|
978
|
+
tenantId: string | null;
|
|
979
|
+
/** The tenant domain (e.g. contoso.onmicrosoft.com) derived from the UPN */
|
|
980
|
+
tenantDomain: string | null;
|
|
981
|
+
/**
|
|
982
|
+
* Whether the current user is a B2B guest in this tenant.
|
|
983
|
+
* True when the home tenant (iss claim) differs from the resource tenant (tid claim).
|
|
984
|
+
*/
|
|
985
|
+
isGuestUser: boolean;
|
|
986
|
+
/** The user's home tenant ID (where their identity lives) */
|
|
987
|
+
homeTenantId: string | null;
|
|
988
|
+
/** The resource tenant ID (the tenant the token was issued for) */
|
|
989
|
+
resourceTenantId: string | null;
|
|
990
|
+
/** Raw idTokenClaims for advanced usage */
|
|
991
|
+
claims: Record<string, any> | null;
|
|
992
|
+
}
|
|
993
|
+
interface UseTenantReturn extends TenantInfo {
|
|
994
|
+
/** Whether the user is authenticated */
|
|
995
|
+
isAuthenticated: boolean;
|
|
996
|
+
}
|
|
997
|
+
/**
|
|
998
|
+
* Hook that exposes tenant context for the currently authenticated user.
|
|
999
|
+
*
|
|
1000
|
+
* @remarks
|
|
1001
|
+
* Detects B2B guest users by comparing the `iss` (issuer / home tenant) claim
|
|
1002
|
+
* against the `tid` (resource tenant) claim. When they differ the user is a
|
|
1003
|
+
* cross-tenant guest.
|
|
1004
|
+
*
|
|
1005
|
+
* @example
|
|
1006
|
+
* ```tsx
|
|
1007
|
+
* 'use client';
|
|
1008
|
+
* import { useTenant } from '@chemmangat/msal-next';
|
|
1009
|
+
*
|
|
1010
|
+
* export default function TenantBadge() {
|
|
1011
|
+
* const { tenantDomain, isGuestUser, tenantId } = useTenant();
|
|
1012
|
+
*
|
|
1013
|
+
* return (
|
|
1014
|
+
* <div>
|
|
1015
|
+
* <span>{tenantDomain}</span>
|
|
1016
|
+
* {isGuestUser && <span className="badge">Guest</span>}
|
|
1017
|
+
* </div>
|
|
1018
|
+
* );
|
|
1019
|
+
* }
|
|
1020
|
+
* ```
|
|
1021
|
+
*/
|
|
1022
|
+
declare function useTenant(): UseTenantReturn;
|
|
1023
|
+
|
|
927
1024
|
interface GraphApiOptions extends RequestInit {
|
|
928
1025
|
/**
|
|
929
1026
|
* Scopes required for the API call
|
|
@@ -1798,6 +1895,16 @@ interface AuthMiddlewareConfig {
|
|
|
1798
1895
|
* Custom authentication check function
|
|
1799
1896
|
*/
|
|
1800
1897
|
isAuthenticated?: (request: NextRequest) => boolean | Promise<boolean>;
|
|
1898
|
+
/**
|
|
1899
|
+
* Tenant access configuration (v5.1.0).
|
|
1900
|
+
* Validated against the account stored in the session cookie.
|
|
1901
|
+
*/
|
|
1902
|
+
tenantConfig?: MultiTenantConfig;
|
|
1903
|
+
/**
|
|
1904
|
+
* Path to redirect to when tenant access is denied (v5.1.0).
|
|
1905
|
+
* @default '/unauthorized'
|
|
1906
|
+
*/
|
|
1907
|
+
tenantDeniedPath?: string;
|
|
1801
1908
|
/**
|
|
1802
1909
|
* Enable debug logging
|
|
1803
1910
|
* @default false
|
|
@@ -1845,4 +1952,4 @@ interface ServerSession {
|
|
|
1845
1952
|
accessToken?: string;
|
|
1846
1953
|
}
|
|
1847
1954
|
|
|
1848
|
-
export { AccountList, type AccountListProps, AccountSwitcher, type AccountSwitcherProps, AuthGuard, type AuthGuardProps, type AuthMiddlewareConfig, type AuthProtectionConfig, AuthStatus, type AuthStatusProps, type CustomTokenClaims, type DebugLoggerConfig, ErrorBoundary, type ErrorBoundaryProps, type GraphApiOptions, MSALProvider, MicrosoftSignInButton, type MicrosoftSignInButtonProps, type MsalAuthConfig, MsalAuthProvider, type MsalAuthProviderProps, MsalError, type PageAuthConfig, ProtectedPage, type RetryConfig, type ServerSession, SignOutButton, type SignOutButtonProps, type UseGraphApiReturn, type UseMsalAuthReturn, type UseMultiAccountReturn, type UseRolesReturn, type UseTokenRefreshOptions, type UseTokenRefreshReturn, type UseUserProfileReturn, UserAvatar, type UserAvatarProps, type UserProfile, type ValidatedAccountData, type ValidationError, type ValidationResult, type ValidationWarning, type WithAuthOptions, createAuthMiddleware, createMissingEnvVarError, createMsalConfig, createRetryWrapper, createScopedLogger, displayValidationResults, getDebugLogger, getMsalInstance, isValidAccountData, isValidRedirectUri, isValidScope, retryWithBackoff, safeJsonParse, sanitizeError, useGraphApi, useMsalAuth, useMultiAccount, useRoles, useTokenRefresh, useUserProfile, validateConfig, validateScopes, withAuth, withPageAuth, wrapMsalError };
|
|
1955
|
+
export { AccountList, type AccountListProps, AccountSwitcher, type AccountSwitcherProps, AuthGuard, type AuthGuardProps, type AuthMiddlewareConfig, type AuthProtectionConfig, AuthStatus, type AuthStatusProps, type CustomTokenClaims, type DebugLoggerConfig, ErrorBoundary, type ErrorBoundaryProps, type GraphApiOptions, MSALProvider, MicrosoftSignInButton, type MicrosoftSignInButtonProps, type MsalAuthConfig, MsalAuthProvider, type MsalAuthProviderProps, MsalError, type MultiTenantConfig, type PageAuthConfig, ProtectedPage, type RetryConfig, type ServerSession, SignOutButton, type SignOutButtonProps, type TenantAuthConfig, type TenantInfo, type UseGraphApiReturn, type UseMsalAuthReturn, type UseMultiAccountReturn, type UseRolesReturn, type UseTenantReturn, type UseTokenRefreshOptions, type UseTokenRefreshReturn, type UseUserProfileReturn, UserAvatar, type UserAvatarProps, type UserProfile, type ValidatedAccountData, type ValidationError, type ValidationResult, type ValidationWarning, type WithAuthOptions, createAuthMiddleware, createMissingEnvVarError, createMsalConfig, createRetryWrapper, createScopedLogger, displayValidationResults, getDebugLogger, getMsalInstance, isValidAccountData, isValidRedirectUri, isValidScope, retryWithBackoff, safeJsonParse, sanitizeError, useGraphApi, useMsalAuth, useMultiAccount, useRoles, useTenant, useTenantConfig, useTokenRefresh, useUserProfile, validateConfig, validateScopes, withAuth, withPageAuth, wrapMsalError };
|